Abstract

Introduction

In UVA’s LinkLab, as a part of the Living Link Lab Program, there is a significant amount of environmental, occupancy data, and HVAC system operational data available for analysis. This presents an opportunity for a detailed case study of the performance of an HVAC system among multiple metrics outside of just temperature and humidity with the intention of improving HVAC control systems’ ability to maintain occupant comfort with reduced energy consumption. Investigation of multiple metrics of occupant comfort, whether a given room even has occupants which require comfort, various metrics of system operation, and energy consumption consumption (actual and calculated) has the potential to produce a environmental model which may aid in the development of an improved policy for the HVAC system control problem.

Considering HVAC usage accounts for 30% of total commercial building energy consumption (US Dept. of Energy Commissioned Report on Energy Savings Potential and RD&D Opportunities for Commercial Building HVAC Systems, 2017), there is significant environmental and economic incentive to reducing the energy load of HVAC systems both for regulators and commercial operators. This same commissioned report cites “Technology Enhancements for Current Systems” as one of four groups of high priority technology options, with “Advanced HVAC Sensors” as the top ranked technology within this category at an estimated Technical Energy Savings Potential (Quadrillion BTU/yr.) of 0.63, lending particular credence to the idea that advanced sensing combined with more efficient control could be a significant contributor to reduced HVAC system burden on energy resources.

This project will investigate the first phase of determining if it possible to create a more efficient control policy for HVAC systems by developing a model of energy consumption calculated from system operation metrics, validating this model with a limited amount of actual collected energy usage data, and attempting to forecast energy demand with this data.

The data and the data-generating process

The data which will be analyzed consists of data exported from an internal UVA server which hosts all HVAC system data related to Olsson Hall and the Link Lab. Additionally, local weather data on humidity, atmospheric pressure, and local temperature data from the KVACHARL114 station attached to Olsson hall will be obtained as potential predictors of energy consumption.

The Data

library(dplyr)
library(forecast)
package 㤼㸱forecast㤼㸲 was built under R version 4.0.5Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
library(fable)
Loading required package: fabletools
package 㤼㸱fabletools㤼㸲 was built under R version 4.0.4
Attaching package: 㤼㸱fabletools㤼㸲

The following objects are masked from 㤼㸱package:forecast㤼㸲:

    accuracy, forecast
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ---------------------------------------------------------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.0.6     v stringr 1.4.0
v tidyr   1.1.2     v forcats 0.5.1
v readr   1.4.0     
package 㤼㸱stringr㤼㸲 was built under R version 4.0.5-- Conflicts ------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(lubridate)
package 㤼㸱lubridate㤼㸲 was built under R version 4.0.4
Attaching package: 㤼㸱lubridate㤼㸲

The following objects are masked from 㤼㸱package:base㤼㸲:

    date, intersect, setdiff, union
library(fpp3)
-- Attaching packages --------------------------------------------------------------------------------------------- fpp3 0.4.0 --
v tsibble     1.0.0     v feasts      0.2.1
v tsibbledata 0.3.0     
package 㤼㸱tsibbledata㤼㸲 was built under R version 4.0.4package 㤼㸱feasts㤼㸲 was built under R version 4.0.4-- Conflicts -------------------------------------------------------------------------------------------------- fpp3_conflicts --
x lubridate::date()      masks base::date()
x dplyr::filter()        masks stats::filter()
x fabletools::forecast() masks forecast::forecast()
x tsibble::intersect()   masks base::intersect()
x tsibble::interval()    masks lubridate::interval()
x dplyr::lag()           masks stats::lag()
x tsibble::setdiff()     masks base::setdiff()
x tsibble::union()       masks base::union()
library(ggplot2)
library(plotly)
package 㤼㸱plotly㤼㸲 was built under R version 4.0.4Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: 㤼㸱plotly㤼㸲

The following object is masked from 㤼㸱package:ggplot2㤼㸲:

    last_plot

The following object is masked from 㤼㸱package:stats㤼㸲:

    filter

The following object is masked from 㤼㸱package:graphics㤼㸲:

    layout
load(file="C:\\Users\\canea\\Documents\\UVA\\Spring 2021\\Timeseries\\neale-caleb\\data\\cleanedData.Rdata")

Air Handling Unit Level Data

Index: Time (30min)

Key: HVAC Air Handling Unit (AHU2E or AHU2W)

Values of Interest: - SAT - Output Air Temperature (deg C) - MAT - Input Air Temperature (deg C) - SAF - Air Supply Flow (CFM) - SAFSP - Air Supply Flow Set point (CFM) - SAEnthalpy - Output air enthalpy (calculated, kW) - MAEnthalpy - Input air enthalpy (calculated, kW) - totalHeat - Change in enthalpy (calculated, kW) - fanEnergy - Energy used by fan (calculated, kW)

head(equip)

Room Level Data

Index: Time (30min)

Key: Room in Olsson Hall

Values: - SAF - Supply Air Flow (CFM) - outputTemp - Reheated air temperature from room level treatment (deg C) - ZNT - Room temperature setpoint (deg C) - SAFSP - Supply air flow setpoint (CFM) - equipment - AHU which serves given room (AHU2E or AHU2W) - inputTemp - Air temperature from AHU given to room for reheat (deg C) - inputEnthalpy - Energy of input air (calculated, kW) - outputEnthalpy - Energy of output air (calculated, kW) - totalHeat - Energy used in reheat (calculated, kW)

head(rooms)

Weather Data

Index: Time (5min)

Key: StationID, KVACHARL114

Values: - humidityAvg - Average relative humidity over 5 min interval (%) - tempAvg - Average temperature over 5 min interval (deg C) - pressureMax - Maximum air pressure over 5 min interval (torr need to confirm unit)

head(weather)

Aggregated Energy

Index: Time (30min)

Key: HVAC Air Handling Unit (AHU2E or AHU2W)

Values: - totalHeat.AHU - Energy used in AHU level treatment (calculated, kW) - fanEnergy - Energy used by fan (calculated, kW) - totalHeat.room - Energy used in room level treatment (calculated, kW) - totalEnergy - sum of all three above energy categories (calculated, kW)

head(totalEnergyDF %>% filter(!is.na(totalEnergy)))
autoplot(totalEnergyDF, .vars = totalEnergy) + ylab("Calculated System Energy (kW)")

Data Generating Process

System Description and Terminology

The HVAC system under consideration is a VAV (variable air volume) system which consists of two air handling units (AHU) and VAV boxes. VAV systems manage the temperature of the different rooms in the building by providing specific volumes of air to each room using equipment known as VAV boxes. At the VAV box, air may be reheated to provide the room with the correct temperature of air needed to maintain the environment at the given setpoint. Our simplified model of the AHU consists of hot and cold water coils for heating/cooling, a return air fan, and a supply air fan. Each VAV box consists of a vent regulating air volume and a heating coil.

Definitions of Air Types

Return air is defined as air which is being returned from the conditioned environment. In this system, return air is mixed with outdoor air to produce mixed air. Mixed air serves as the input to the conditioning system at the AHU level. Once the air is treated (heating/cooling, humidity removal) by the AHU, it is output as supply air. This supply air is then provided to each VAV box for additional heating as needed, producing final supply air. As this lack of distinction between these two versions of “supply air” may be confusing, this analysis will adopt the terms “input air” and “output air” when discussing both the VAV and AHU treatment processes.

Air Supply Flow

Air supply flow is measured at the VAV box level and aggregated to determine AHU air volumes.

Enthalpy Change

As treatment can occur at both the AHU and VAV box, enthaply change (change in energy due to heating/cooling and humidity removal) must be calculated at both stages and then aggregated to find total enthalpy change at a given time.

Weather Data

Weather data was collected from Need source for this data using an API and then merged into the data using the times. The location of this weather data is TBD and was used to estimate local temperature, pressure, and relative humidity. Check units

Exploration of

Plan for Analysis

The primary goal of this analysis is to generate an effective model of how HVAC system operation affects energy consumption over time, which can be divided into three parts:

Calculate Energy Usage from HVAC Operational Metrics

The primary usages of energy in this HVAC system come from treatment at the AHU, treatment at the VAV box, and fan operation in the AHU. Calculations for treatment at the AHU and VAV box level leverage the same equations, and fan equations can be leveraged to estimate fan energy usage.

Air Treatment

The change in energy due to air treatment (at either AHU or VAV) can be divided into latent and sensible heat. Changes in latent heat arise from humidity added or removed from the air whereas sensible heat is affected by changes in air temperature. Enthalpy change accounts for both latent and sensible heat as is calculated using fix with Zotero (https://rdrr.io/github/chrras/climateeng/man/). Equation 1, below, can then be used to determine total heat by combining calculated enthalpy change with collected data on air volume flow.

Equation 1, Latent and Sensible Heat

Zotero source h_t = ρ*q*dh

where:

h_t = total heat (kW)
q = air volume flow (m3/s)
ρ = density of air (1.202 kg/m3)
dh = enthalpy difference (kJ/kg)

Load data

load("C:\\Users\\canea\\Documents\\UVA\\Spring 2021\\Timeseries\\neale-caleb\\data\\preCalcData.RData")

Calculate Enthalpy for Mixed and supply Air, then total heat

library(climateeng)

#Define constants
RHconstant = 0.010
density = 1.202
CFMtoM_SConverstionFactor = 0.00047194745

# Calculate AHU level enthalpy
equip$SAEnthalpy = enthalpy(equip$SAT, RHconstant) 
equip$MAEnthalpy = enthalpy(equip$MAT, RHconstant)
equip$totalHeat = abs(equip$SAEnthalpy -equip$MAEnthalpy)*CFMtoM_SConverstionFactor*equip$SAF*density

Get input air temp for each room

# create table mapping room to equpment from system documentation
AHU_2E <- c(241, 243, 245, 247, 249, 251, 253, 257, 255, 259, 263, 261, 240, "C244", 244, 260, 213, 217, 225, 218, "C230", 220, "C210", "T212", "T218", "C216", "C214", "T210", 256, 229, 231, 223, "C227", "C211", 254, "C250", 258, "C213", 221) 

AHU_2W <- c(269, 267, 265, 273, 271, 275, 277, 279, 281, 283, 285, 274, 286, 204, 208, 272, 270, "C260", "C200", "C201", 203, 276, "C280", "C270", 211, 201)

rooms_tbl <- rbind(tibble('room' = AHU_2E, 'equipment' = "AHU2E"), tibble('room' = AHU_2W, 'equipment' = "AHU2W"))

# extract relevant information from room coding
rooms$cleaned_room = str_extract(rooms$room, "C\\d{3}|^\\d{3}")

# get relevant equipment for each room 
rooms = left_join(rooms, rooms_tbl, by=c("cleaned_room" = "room"))

rooms %>% filter(!is.na(room)) -> rooms

rooms = rooms %>% select(-cleaned_room) -> rooms

# get input air temperature for each room
rel = equip %>% select(SAT)
rooms = left_join(rooms, rel, by=c("equipment", "time"))

# rename columns for clarity
colnames(rooms)[3] = "outputTemp"
colnames(rooms)[8] = "inputTemp"

Calculate energy consumption from room level treatment

rooms$inputEnthalpy = enthalpy(rooms$inputTemp, RHconstant) 
rooms$outputEnthalpy = enthalpy(rooms$outputTemp, RHconstant)
rooms$totalHeat = abs(rooms$inputEnthalpy - rooms$outputEnthalpy)*CFMtoM_SConverstionFactor*rooms$SAF*density

Fans

Power used by a fan can be calculated using equation 2, below. Pressure set to a constant typical of commercial HVAC fans, fan efficiency will be assumed to be 60%, and air volume is measured.

Equation 2, Power Used by Fan

Zotero source P = dp*q/mu

where:

mu = fan efficiency (values between 0 - 1)
dp = total pressure (Pa)
q = air volume delivered by the fan (m3/s)
P = power used by the fan (W, Nm/s)

Fan Energy

# Set constants
fanEfficiencyCoef = 0.6
pressure = 4000
Wto_kW =1000

# Calculate energy (2* for two fans)
equip$fanEnergy = 2*equip$SAF*CFMtoM_SConverstionFactor*pressure/fanEfficiencyCoef/Wto_kW

Create tsibble with room and AHU heat and Fan Energy

rooms %>% group_by(equipment) %>% summarise(totalHeat = sum(totalHeat)) -> roomAHUHeat

equip %>% select(totalHeat, fanEnergy) %>% inner_join(roomAHUHeat, by=c("time", "equipment"), suffix = c(".AHU", ".room")) -> totalEnergyDF

totalEnergyDF$totalHeat = totalEnergyDF$totalHeat.AHU + totalEnergyDF$totalHeat.room
totalEnergyDF$totalEnergy = totalEnergyDF$totalHeat + totalEnergyDF$fanEnergy

Seasonality of Energy Consumption

totalEnergyDF = fill_gaps(totalEnergyDF)
gg_season(totalEnergyDF, totalEnergy, period = "week")

gg_season(totalEnergyDF, totalEnergy, period = "day")

gg_season(totalEnergyDF, totalEnergy, period = "month")

Energy consumption has a clear daily cycle where the system is off over night then turns on at a time early enough in the morning to ensure that the internal temperature in the building meets the setpoint by the time occupants arrive. The shifting start times throughout the year as seen on the daily seasonal plot are a result of this control mechanism which predicts how long the system will need to arrive at the setpoint given the current internal temperature and begins treatment accordingly. During colder/warmer seasons, internal temperature drifts farther from the setpoint overnight and thus takes longer to return to the setpoint.

AHU2W appears to have a lower bound of energy consumption above that of AHU2E. Investigating the components of totalEnergy reveals that this lower bound comes from increased nighttime fan energy and AHU level energy consumption.

gg_season(fill_gaps(equip), fanEnergy, period = "day") + ylab("Fan Energy (kW)")

gg_season(fill_gaps(roomAHUHeat), totalHeat, period = "day") + ylab("Room Level Reheat Energy (kW)")

gg_season(fill_gaps(equip), totalHeat, period = "day") + ylab("AHU Level Treatment Energy (kW)")

Breaking down energy consumption in this manner also reveals that fan energy consumption follows a daily cycle but is not as significantly influenced by time of year as room or AHU treatment consumption. Interestingly as well, though both AHU and room energy consumption show a yearly trend, they appear to be nearly inverse. Room consumption is highest on blue days and lowest on pink, while AHU consumption appears to be highest on orange and lowest on blue.

Relationship of Local Weather and Energy Consumption

weather_merge = weather

# shift weather data by a minute to allow for merging
weather_merge$obsTimeLocal = weather_merge$obsTimeLocal + 60

# merge data
left_join(totalEnergyDF, weather_merge, by=c("time" = "obsTimeLocal")) %>% filter(!is.na(totalEnergy))-> weather_energy

# plot, filtering out low energy values for when HVAC system is "off"
ggplot(data = weather_energy %>% filter(totalEnergy > 50), aes(x=tempAvg, y=totalEnergy)) + geom_point() + geom_smooth()

As the previous charts showing lower consumption in shoulder seasons implied, energy consumption appears to be roughly quadratic with respect to temperature.

Validation of Estimated Energy Consumption

Historical data is available for building-wide energy consumption, divided into:

  • chilledWater (cooling)
  • heating
  • electricity
head(buildingEnergy)

As HVAC operation represents a significant part of building energy consumption, we would expect that trends in and changes of HVAC system energy consumption would closely track with building wide energy consumption. Calculated historical energy consumption is plotted next to building-wide energy consumption for inspection:

Determine cooling state and evalutate relationship of calculated energy consumption in cooling state and actual historical chilled water consumption

library(plotly)

equip %>% filter(!is.na(SAT) & !is.na(MAT)) -> equipVerify

# determine cooling status based on comparative temperature of input and output air 
equipVerify <- equipVerify %>% mutate(cooling = 
  if_else(
    MAT > SAT, 1, 0
  )
)

left_join(equipVerify, buildingEnergy, by="time") -> coolingVerify

coolingVerify <- coolingVerify %>% filter(cooling == 1) %>% as_tsibble(key = equipment, index = time)

# plot and model actual cooling energy consumption as a funciton of calcualted heating consumption
ggplot(data = coolingVerify, aes(x=chilledWater, y=totalHeat)) + geom_point() + geom_smooth(method = "lm")


fig <- plot_ly(coolingVerify, x = ~time, y = ~totalHeat, name = 'AHU Heat', type = 'scatter', mode = 'lines') 
fig %>% add_trace(y = ~(chilledWater*1000)/3412.142, name = 'Chilled Water', mode = 'lines')

coolingLM = lm(chilledWater~totalHeat, data = coolingVerify)

summary(coolingLM)

Call:
lm(formula = chilledWater ~ totalHeat, data = coolingVerify)

Residuals:
   Min     1Q Median     3Q    Max 
-842.1 -161.9 -100.5  154.3  890.0 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 106.01886    3.52299   30.09   <2e-16 ***
totalHeat     4.57092    0.09118   50.13   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 250.1 on 11108 degrees of freedom
  (614 observations deleted due to missingness)
Multiple R-squared:  0.1845,    Adjusted R-squared:  0.1844 
F-statistic:  2513 on 1 and 11108 DF,  p-value: < 2.2e-16

A linear relationship between the calculated amount of energy used in cooling and historical chilled water consumption appears to exist, though a linear model between these two quantities shows an R^2 of 0.1844. This suggests that tuning within set parameters used in calculated energy consumption might improve the accuracy of the calculations.

Evalutate relationship of calculated energy consumption in heating state and actual historical chilled water consumption


# aggregate room level contributions to energy consumption by AHU
rooms %>% group_by(equipment) %>% summarise(totalHeat = sum(totalHeat)) -> roomAHUHeat

# join  room and equipment level data
equip %>% inner_join(roomAHUHeat, by=c("time", "equipment"), suffix = c(".AHU", ".room")) -> totalEnergyDF

# create DF for enery verificaiton and determine heating status based on comparative temperature of input and output air
totalEnergyDF %>% filter(!is.na(SAT) & !is.na(MAT)) -> totalEnergyDFVerify

totalEnergyDFVerify <- totalEnergyDFVerify %>%
  mutate(isHeating = if_else(
    SAT > MAT, 1, 0
    )
  )

# join in actual energy consumption data
left_join(totalEnergyDFVerify, buildingEnergy, by="time") -> heatingVerify

heatingVerify %>% filter(!is.na(heatingVerify$isHeating)) -> heatingVerify

# calculate total heating energy based on AHU heating status 
heatingVerify <- heatingVerify %>%
  mutate(heatEnergyCalc = if_else(
    isHeating == 1, totalHeat.AHU + totalHeat.room, totalHeat.room
    )
  )

# plot and model actual heating energy consumption as a funciton of calcualted heating consumption
ggplot(data = heatingVerify, aes(x=heating, y=heatEnergyCalc)) + geom_point() + geom_smooth(method = "lm")


fig <- plot_ly(heatingVerify, x = ~time, y = ~heatEnergyCalc, name = 'AHU Heat', type = 'scatter', mode = 'lines') 

# heating is adjusted from kBTU to kW
fig %>% add_trace(y = ~(heating*1000)/3412.142, name = 'Heating', mode = 'lines')

heatingLM = lm(heating~heatEnergyCalc, data = heatingVerify)

summary(heatingLM)

Call:
lm(formula = heating ~ heatEnergyCalc, data = heatingVerify)

Residuals:
   Min     1Q Median     3Q    Max 
-559.0 -154.0 -133.0  135.4  783.2 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)    214.33108    1.82976  117.14   <2e-16 ***
heatEnergyCalc   2.21688    0.04549   48.73   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 242.3 on 25805 degrees of freedom
  (1749 observations deleted due to missingness)
Multiple R-squared:  0.08428,   Adjusted R-squared:  0.08425 
F-statistic:  2375 on 1 and 25805 DF,  p-value: < 2.2e-16

Modeling actual heat energy consumption as a linear function of calculated heat consumption results in an R^2 of only 0.084, though the model performs better than the null.

Further investigation is clearly needed to determine whether there are other significant contributors to consumption of heating and cooling energy within the building, or if the model needs more development (tuning of constant parameters used in calclations potentially). As a further point of research, having energy readings directly metered from the HVAC unit would likely provide significantly more accurate data, especially if developing an improved control mechanism is ever attempted.

Formal model of data-generating process

Given the previously shown daily cycle of the data, shoulder season behaviour, and quadratic relationship with local temperate, regression with ARIMA errors seems a reasonable place to begin to model the data generating process behind total energy use in the system.

An investigation of lags and autocorrelation will provide the basis for the parameter selection of the ARIMA model.

Lag Plots

totalEnergyDF %>% select(totalEnergy) %>% filter(equipment == "AHU2W") %>% gg_lag(y=totalEnergy, geom = "point")
Removed 15 rows containing missing values (gg_lag).

Potentially given the lower bound previously seen on AHU2W energy consumption, a stronger relationship appears in the lags of AHU2E than AHU2W.

Autocorrelation Plots

# ACFs
totalEnergyDF %>% filter(equipment == "AHU2E") %>% ACF(totalEnergy, lag_max = 140) %>% autoplot() + ylab("AHU2E ACF")

totalEnergyDF %>% filter(equipment == "AHU2W") %>% ACF(totalEnergy, lag_max = 140) %>% autoplot() + ylab("AHU2W ACF")


# PACFs
totalEnergyDF %>% filter(equipment == "AHU2E") %>% PACF(totalEnergy, lag_max = 140) %>% autoplot() + ylab("AHU2E PACF")

totalEnergyDF %>% filter(equipment == "AHU2W") %>% PACF(totalEnergy, lag_max = 140) %>% autoplot() + ylab("AHU2W PACF")

Given a 48 period lag corresponds to one day, the behaviour seen in the ACF plots show exactly what we might expect; ACF is highest at multiples of 24 hours from a given point. PACF plots also show highest PACF values at about the 24 hour mark, though additional 24 hour extensions provide significantly less information.

However, given the likely yearly seasonality of the data, an investigation into the differences of the data is needed.

Differencing

totalEnergyDF %>% filter(equipment == "AHU2E") %>% gg_tsdisplay(difference(totalEnergy), plot_type = "partial", lag_max = 140)

totalEnergyDF %>% filter(equipment == "AHU2W") %>% gg_tsdisplay(difference(totalEnergy), plot_type = "partial", lag_max = 140)

Preliminary ARIMA Modeling

The ACF is suggestive of an MA(52) model while the PACF suggests an AR(54) model, so ARIMA(0, 1, 52) and ARIMA(54, 1, 0) will be part of the initially fit models. However, a more appropriate approach would likely be setting the seasonality of the data to daily (48 periods) and attempting ARIMA from there. This may not accurately address yearlong seasonal trends, but weather data may account for this in a synamic regression model.

This model seems to capture the daily cycle of energy consumption quite well, but doesn’t well account for the influence of temperature or the general variation in the data. To determine if another ARIMA model would perform better, I’ll use fable::ARIMA to investigate three additional ARIMA models before attempting dynamic regression with ARIMA errors.

Dynamic Regression with ARIMA Errors

The ARIMA model seems to capture the daily cycle in the data well, but daily and seasonal variation exists and this variation could likely be explained by daily and seasonal changes in outdoor temperatures. To capture this variation, dynamic regression with ARIMA error can be applied.

report(dynRegTrain)
Series: totalEnergy 
Model: LM w/ ARIMA(5,0,0)(1,1,0)[48] errors 

Coefficients:
         ar1      ar2     ar3      ar4     ar5     sar1  tempAvg  I(tempAvg^2)
      0.9032  -0.1656  0.1168  -0.1735  0.1639  -0.2458  -0.3918        0.0172
s.e.  0.0094   0.0127  0.0127   0.0128  0.0094   0.0096   0.2496        0.0074

sigma^2 estimated as 272.8:  log likelihood=-49011.45
AIC=98040.9   AICc=98040.91   BIC=98107.41

This dynamic regression model seems to be the best at capturing additional daily variation which may be attributed to temperature. Looking at the residuals on a weekly basisi over the year, it can be seen that the yearly seasonal component is not being completely accounted for, especially in the changing startup time of the system over the course of the year.

Model of the Data Generating Process

The data generating process for system energy consumption can be modeled as a dynamic regression with ARIMA errors in the form:

y = β_0 + β_1*tempAvg + β_2*tempAvg^2 + ε

where ε is ARIMA (5,0,0,)(1,1,0)[48]

Discussion of the statistical model

Describe how the formal statistical model captures and aligns with the narrative of the data-generating process. Flag any statistical challenges raised by the data generating process, e.g. selection bias; survivorship bias omitted variables bias etc.

References

LS0tDQp0aXRsZTogIlByb2plY3QgUHJvcG9zYWwgKERyYWZ0KSINCmF1dGhvcjogIkNhbGViIE5lYWxlIg0KZGF0ZTogIlNwcmluZyAyMDIxIg0Kb3V0cHV0Og0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0Kc3VidGl0bGU6IE9wdGltaXppbmcgSFZBQyBPcGVyYXRpb24gZm9yIE9jY3VwYW50IENvbWZvcnQgYW5kIEVuZXJneSBTYXZpbmdzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KIyBBYnN0cmFjdA0KDQojIEludHJvZHVjdGlvbg0KSW4gVVZBJ3MgTGlua0xhYiwgYXMgYSBwYXJ0IG9mIHRoZSBMaXZpbmcgTGluayBMYWIgUHJvZ3JhbSwgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBhbW91bnQgb2YgZW52aXJvbm1lbnRhbCwgb2NjdXBhbmN5IGRhdGEsIGFuZCBIVkFDIHN5c3RlbSBvcGVyYXRpb25hbCBkYXRhIGF2YWlsYWJsZSBmb3IgYW5hbHlzaXMuIFRoaXMgcHJlc2VudHMgYW4gb3Bwb3J0dW5pdHkgZm9yIGEgZGV0YWlsZWQgY2FzZSBzdHVkeSBvZiB0aGUgcGVyZm9ybWFuY2Ugb2YgYW4gSFZBQyBzeXN0ZW0gYW1vbmcgbXVsdGlwbGUgbWV0cmljcyBvdXRzaWRlIG9mIGp1c3QgdGVtcGVyYXR1cmUgYW5kIGh1bWlkaXR5IHdpdGggdGhlIGludGVudGlvbiBvZiBpbXByb3ZpbmcgSFZBQyBjb250cm9sIHN5c3RlbXMnIGFiaWxpdHkgdG8gbWFpbnRhaW4gb2NjdXBhbnQgY29tZm9ydCB3aXRoIHJlZHVjZWQgZW5lcmd5IGNvbnN1bXB0aW9uLiBJbnZlc3RpZ2F0aW9uIG9mIG11bHRpcGxlIG1ldHJpY3Mgb2Ygb2NjdXBhbnQgY29tZm9ydCwgd2hldGhlciBhIGdpdmVuIHJvb20gZXZlbiBoYXMgb2NjdXBhbnRzIHdoaWNoIHJlcXVpcmUgY29tZm9ydCwgdmFyaW91cyBtZXRyaWNzIG9mIHN5c3RlbSBvcGVyYXRpb24sIGFuZCBlbmVyZ3kgY29uc3VtcHRpb24gY29uc3VtcHRpb24gKGFjdHVhbCBhbmQgY2FsY3VsYXRlZCkgaGFzIHRoZSBwb3RlbnRpYWwgdG8gcHJvZHVjZSBhIGVudmlyb25tZW50YWwgbW9kZWwgd2hpY2ggbWF5IGFpZCBpbiB0aGUgZGV2ZWxvcG1lbnQgb2YgYW4gaW1wcm92ZWQgcG9saWN5IGZvciB0aGUgSFZBQyBzeXN0ZW0gY29udHJvbCBwcm9ibGVtLiANCg0KQ29uc2lkZXJpbmcgSFZBQyB1c2FnZSBhY2NvdW50cyBmb3IgMzAlIG9mIHRvdGFsIGNvbW1lcmNpYWwgYnVpbGRpbmcgZW5lcmd5IGNvbnN1bXB0aW9uIChVUyBEZXB0LiBvZiBFbmVyZ3kgQ29tbWlzc2lvbmVkIFJlcG9ydCBvbiBFbmVyZ3kgU2F2aW5ncyBQb3RlbnRpYWwgYW5kIFJEJkQgT3Bwb3J0dW5pdGllcyBmb3IgQ29tbWVyY2lhbCBCdWlsZGluZyBIVkFDIFN5c3RlbXMsIDIwMTcpLCB0aGVyZSBpcyBzaWduaWZpY2FudCBlbnZpcm9ubWVudGFsIGFuZCBlY29ub21pYyBpbmNlbnRpdmUgdG8gcmVkdWNpbmcgdGhlIGVuZXJneSBsb2FkIG9mIEhWQUMgc3lzdGVtcyBib3RoIGZvciByZWd1bGF0b3JzIGFuZCBjb21tZXJjaWFsIG9wZXJhdG9ycy4gVGhpcyBzYW1lIGNvbW1pc3Npb25lZCByZXBvcnQgY2l0ZXMgIlRlY2hub2xvZ3kgRW5oYW5jZW1lbnRzIGZvciBDdXJyZW50IFN5c3RlbXMiIGFzIG9uZSBvZiBmb3VyIGdyb3VwcyBvZiBoaWdoIHByaW9yaXR5IHRlY2hub2xvZ3kgb3B0aW9ucywgd2l0aCAgIkFkdmFuY2VkIEhWQUMgU2Vuc29ycyIgYXMgdGhlIHRvcCByYW5rZWQgdGVjaG5vbG9neSB3aXRoaW4gdGhpcyBjYXRlZ29yeSBhdCBhbiBlc3RpbWF0ZWQgVGVjaG5pY2FsIEVuZXJneSBTYXZpbmdzIFBvdGVudGlhbCAoUXVhZHJpbGxpb24gQlRVL3lyLikgb2YgMC42MywgbGVuZGluZyBwYXJ0aWN1bGFyIGNyZWRlbmNlIHRvIHRoZSBpZGVhIHRoYXQgYWR2YW5jZWQgc2Vuc2luZyBjb21iaW5lZCB3aXRoIG1vcmUgZWZmaWNpZW50IGNvbnRyb2wgY291bGQgYmUgYSBzaWduaWZpY2FudCBjb250cmlidXRvciB0byByZWR1Y2VkIEhWQUMgc3lzdGVtIGJ1cmRlbiBvbiBlbmVyZ3kgcmVzb3VyY2VzLg0KDQpUaGlzIHByb2plY3Qgd2lsbCBpbnZlc3RpZ2F0ZSB0aGUgZmlyc3QgcGhhc2Ugb2YgZGV0ZXJtaW5pbmcgaWYgaXQgcG9zc2libGUgdG8gY3JlYXRlIGEgbW9yZSBlZmZpY2llbnQgY29udHJvbCBwb2xpY3kgZm9yIEhWQUMgc3lzdGVtcyBieSBkZXZlbG9waW5nIGEgbW9kZWwgb2YgZW5lcmd5IGNvbnN1bXB0aW9uIGNhbGN1bGF0ZWQgZnJvbSBzeXN0ZW0gb3BlcmF0aW9uIG1ldHJpY3MsIHZhbGlkYXRpbmcgdGhpcyBtb2RlbCB3aXRoIGEgbGltaXRlZCBhbW91bnQgb2YgYWN0dWFsIGNvbGxlY3RlZCBlbmVyZ3kgdXNhZ2UgZGF0YSwgYW5kIGF0dGVtcHRpbmcgdG8gZm9yZWNhc3QgZW5lcmd5IGRlbWFuZCB3aXRoIHRoaXMgZGF0YS4NCg0KIyBUaGUgZGF0YSBhbmQgdGhlIGRhdGEtZ2VuZXJhdGluZyBwcm9jZXNzDQpUaGUgZGF0YSB3aGljaCB3aWxsIGJlIGFuYWx5emVkIGNvbnNpc3RzIG9mIGRhdGEgZXhwb3J0ZWQgZnJvbSBhbiBpbnRlcm5hbCBVVkEgc2VydmVyIHdoaWNoIGhvc3RzIGFsbCBIVkFDIHN5c3RlbSBkYXRhIHJlbGF0ZWQgdG8gT2xzc29uIEhhbGwgYW5kIHRoZSBMaW5rIExhYi4gQWRkaXRpb25hbGx5LCBsb2NhbCB3ZWF0aGVyIGRhdGEgb24gaHVtaWRpdHksIGF0bW9zcGhlcmljIHByZXNzdXJlLCBhbmQgbG9jYWwgdGVtcGVyYXR1cmUgZGF0YSBmcm9tIHRoZSBLVkFDSEFSTDExNCBzdGF0aW9uIGF0dGFjaGVkIHRvIE9sc3NvbiBoYWxsIHdpbGwgYmUgb2J0YWluZWQgYXMgcG90ZW50aWFsIHByZWRpY3RvcnMgb2YgZW5lcmd5IGNvbnN1bXB0aW9uLg0KDQojIyBUaGUgRGF0YQ0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShmb3JlY2FzdCkNCmxpYnJhcnkoZmFibGUpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShmcHAzKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwbG90bHkpDQoNCmxvYWQoZmlsZT0iQzpcXFVzZXJzXFxjYW5lYVxcRG9jdW1lbnRzXFxVVkFcXFNwcmluZyAyMDIxXFxUaW1lc2VyaWVzXFxuZWFsZS1jYWxlYlxcZGF0YVxcY2xlYW5lZERhdGEuUmRhdGEiKQ0KYGBgDQoNCiMjIyBBaXIgSGFuZGxpbmcgVW5pdCBMZXZlbCBEYXRhDQpJbmRleDoNClRpbWUgKDMwbWluKQ0KDQpLZXk6DQpIVkFDIEFpciBIYW5kbGluZyBVbml0IChBSFUyRSBvciBBSFUyVykNCg0KVmFsdWVzIG9mIEludGVyZXN0Og0KLSBTQVQgLSBPdXRwdXQgQWlyIFRlbXBlcmF0dXJlIChkZWcgQykNCi0gTUFUIC0gSW5wdXQgQWlyIFRlbXBlcmF0dXJlICAoZGVnIEMpDQotIFNBRiAtIEFpciBTdXBwbHkgRmxvdyAoQ0ZNKQ0KLSBTQUZTUCAtIEFpciBTdXBwbHkgRmxvdyBTZXQgcG9pbnQgKENGTSkNCi0gU0FFbnRoYWxweSAtIE91dHB1dCBhaXIgZW50aGFscHkgKGNhbGN1bGF0ZWQsIGtXKQ0KLSBNQUVudGhhbHB5IC0gSW5wdXQgYWlyIGVudGhhbHB5IChjYWxjdWxhdGVkLCBrVykNCi0gdG90YWxIZWF0IC0gQ2hhbmdlIGluIGVudGhhbHB5IChjYWxjdWxhdGVkLCBrVykNCi0gZmFuRW5lcmd5IC0gRW5lcmd5IHVzZWQgYnkgZmFuICAoY2FsY3VsYXRlZCwga1cpDQoNCmBgYHtyfQ0KaGVhZChlcXVpcCkNCmBgYA0KDQoNCiMjIyBSb29tIExldmVsIERhdGENCkluZGV4Og0KVGltZSAoMzBtaW4pDQoNCktleToNClJvb20gaW4gT2xzc29uIEhhbGwNCg0KVmFsdWVzOiANCi0gU0FGIC0gU3VwcGx5IEFpciBGbG93IChDRk0pDQotIG91dHB1dFRlbXAgLSBSZWhlYXRlZCBhaXIgdGVtcGVyYXR1cmUgZnJvbSByb29tIGxldmVsIHRyZWF0bWVudCAoZGVnIEMpDQotIFpOVCAtIFJvb20gdGVtcGVyYXR1cmUgc2V0cG9pbnQgKGRlZyBDKQ0KLSBTQUZTUCAtIFN1cHBseSBhaXIgZmxvdyBzZXRwb2ludCAoQ0ZNKQ0KLSBlcXVpcG1lbnQgLSBBSFUgd2hpY2ggc2VydmVzIGdpdmVuIHJvb20gKEFIVTJFIG9yIEFIVTJXKQ0KLSBpbnB1dFRlbXAgLSBBaXIgdGVtcGVyYXR1cmUgZnJvbSBBSFUgZ2l2ZW4gdG8gcm9vbSBmb3IgcmVoZWF0IChkZWcgQykNCi0gaW5wdXRFbnRoYWxweSAtIEVuZXJneSBvZiBpbnB1dCBhaXIgKGNhbGN1bGF0ZWQsIGtXKQ0KLSBvdXRwdXRFbnRoYWxweSAtIEVuZXJneSBvZiBvdXRwdXQgYWlyIChjYWxjdWxhdGVkLCBrVykNCi0gdG90YWxIZWF0IC0gRW5lcmd5IHVzZWQgaW4gcmVoZWF0IChjYWxjdWxhdGVkLCBrVykNCg0KYGBge3J9DQpoZWFkKHJvb21zKQ0KYGBgDQoNCg0KIyMjIFdlYXRoZXIgRGF0YQ0KSW5kZXg6DQpUaW1lICg1bWluKQ0KDQpLZXk6DQpTdGF0aW9uSUQsIEtWQUNIQVJMMTE0DQoNClZhbHVlczoNCi0gaHVtaWRpdHlBdmcgLSBBdmVyYWdlIHJlbGF0aXZlIGh1bWlkaXR5IG92ZXIgNSBtaW4gaW50ZXJ2YWwgKCUpDQotIHRlbXBBdmcgLSBBdmVyYWdlIHRlbXBlcmF0dXJlIG92ZXIgNSBtaW4gaW50ZXJ2YWwgKGRlZyBDKQ0KLSBwcmVzc3VyZU1heCAtIE1heGltdW0gYWlyIHByZXNzdXJlIG92ZXIgNSBtaW4gaW50ZXJ2YWwgKHRvcnIgKipuZWVkIHRvIGNvbmZpcm0gdW5pdCoqKQ0KDQpgYGB7cn0NCmhlYWQod2VhdGhlcikNCmBgYA0KDQoNCiMjIyBBZ2dyZWdhdGVkIEVuZXJneSANCkluZGV4Og0KVGltZSAoMzBtaW4pDQoNCktleToNCkhWQUMgQWlyIEhhbmRsaW5nIFVuaXQgKEFIVTJFIG9yIEFIVTJXKQ0KDQpWYWx1ZXM6DQotIHRvdGFsSGVhdC5BSFUgLSBFbmVyZ3kgdXNlZCBpbiBBSFUgbGV2ZWwgdHJlYXRtZW50IChjYWxjdWxhdGVkLCBrVykNCi0gZmFuRW5lcmd5IC0gRW5lcmd5IHVzZWQgYnkgZmFuICAoY2FsY3VsYXRlZCwga1cpDQotIHRvdGFsSGVhdC5yb29tIC0gIEVuZXJneSB1c2VkIGluIHJvb20gbGV2ZWwgdHJlYXRtZW50IChjYWxjdWxhdGVkLCBrVykNCi0gdG90YWxFbmVyZ3kgLSBzdW0gb2YgYWxsIHRocmVlIGFib3ZlIGVuZXJneSBjYXRlZ29yaWVzIChjYWxjdWxhdGVkLCBrVykNCg0KDQpgYGB7cn0NCmhlYWQodG90YWxFbmVyZ3lERiAlPiUgZmlsdGVyKCFpcy5uYSh0b3RhbEVuZXJneSkpKQ0KYXV0b3Bsb3QodG90YWxFbmVyZ3lERiwgLnZhcnMgPSB0b3RhbEVuZXJneSkgKyB5bGFiKCJDYWxjdWxhdGVkIFN5c3RlbSBFbmVyZ3kgKGtXKSIpDQpgYGANCg0KIyMgRGF0YSBHZW5lcmF0aW5nIFByb2Nlc3MNCg0KIyMjIFN5c3RlbSBEZXNjcmlwdGlvbiBhbmQgVGVybWlub2xvZ3kNClRoZSBIVkFDIHN5c3RlbSB1bmRlciBjb25zaWRlcmF0aW9uIGlzIGEgVkFWICh2YXJpYWJsZSBhaXIgdm9sdW1lKSBzeXN0ZW0gd2hpY2ggY29uc2lzdHMgb2YgdHdvIGFpciBoYW5kbGluZyB1bml0cyAoQUhVKSBhbmQgVkFWIGJveGVzLiBWQVYgc3lzdGVtcyBtYW5hZ2UgdGhlIHRlbXBlcmF0dXJlIG9mIHRoZSBkaWZmZXJlbnQgcm9vbXMgaW4gdGhlIGJ1aWxkaW5nIGJ5IHByb3ZpZGluZyBzcGVjaWZpYyB2b2x1bWVzIG9mIGFpciB0byBlYWNoIHJvb20gdXNpbmcgZXF1aXBtZW50IGtub3duIGFzIFZBViBib3hlcy4gQXQgdGhlIFZBViBib3gsIGFpciBtYXkgYmUgcmVoZWF0ZWQgdG8gcHJvdmlkZSB0aGUgcm9vbSB3aXRoIHRoZSBjb3JyZWN0IHRlbXBlcmF0dXJlIG9mIGFpciBuZWVkZWQgdG8gbWFpbnRhaW4gdGhlIGVudmlyb25tZW50IGF0IHRoZSBnaXZlbiBzZXRwb2ludC4gT3VyIHNpbXBsaWZpZWQgbW9kZWwgb2YgdGhlIEFIVSBjb25zaXN0cyBvZiBob3QgYW5kIGNvbGQgd2F0ZXIgY29pbHMgZm9yIGhlYXRpbmcvY29vbGluZywgYSByZXR1cm4gYWlyIGZhbiwgYW5kIGEgc3VwcGx5IGFpciBmYW4uIEVhY2ggVkFWIGJveCBjb25zaXN0cyBvZiBhIHZlbnQgcmVndWxhdGluZyBhaXIgdm9sdW1lIGFuZCBhIGhlYXRpbmcgY29pbC4gDQoNCiMjIyBEZWZpbml0aW9ucyBvZiBBaXIgVHlwZXMNClJldHVybiBhaXIgaXMgZGVmaW5lZCBhcyBhaXIgd2hpY2ggaXMgYmVpbmcgcmV0dXJuZWQgZnJvbSB0aGUgY29uZGl0aW9uZWQgZW52aXJvbm1lbnQuIEluIHRoaXMgc3lzdGVtLCByZXR1cm4gYWlyIGlzIG1peGVkIHdpdGggb3V0ZG9vciBhaXIgdG8gcHJvZHVjZSBtaXhlZCBhaXIuIE1peGVkIGFpciBzZXJ2ZXMgYXMgdGhlIGlucHV0IHRvIHRoZSBjb25kaXRpb25pbmcgc3lzdGVtIGF0IHRoZSBBSFUgbGV2ZWwuIE9uY2UgdGhlIGFpciBpcyB0cmVhdGVkIChoZWF0aW5nL2Nvb2xpbmcsIGh1bWlkaXR5IHJlbW92YWwpIGJ5IHRoZSBBSFUsIGl0IGlzIG91dHB1dCBhcyBzdXBwbHkgYWlyLiBUaGlzIHN1cHBseSBhaXIgaXMgdGhlbiBwcm92aWRlZCB0byBlYWNoIFZBViBib3ggZm9yIGFkZGl0aW9uYWwgaGVhdGluZyBhcyBuZWVkZWQsIHByb2R1Y2luZyBmaW5hbCBzdXBwbHkgYWlyLiBBcyB0aGlzIGxhY2sgb2YgZGlzdGluY3Rpb24gYmV0d2VlbiB0aGVzZSB0d28gdmVyc2lvbnMgb2YgInN1cHBseSBhaXIiIG1heSBiZSBjb25mdXNpbmcsIHRoaXMgYW5hbHlzaXMgd2lsbCBhZG9wdCB0aGUgdGVybXMgImlucHV0IGFpciIgYW5kICJvdXRwdXQgYWlyIiB3aGVuIGRpc2N1c3NpbmcgYm90aCB0aGUgVkFWIGFuZCBBSFUgdHJlYXRtZW50IHByb2Nlc3Nlcy4NCg0KIyMjIEFpciBTdXBwbHkgRmxvdw0KQWlyIHN1cHBseSBmbG93IGlzIG1lYXN1cmVkIGF0IHRoZSBWQVYgYm94IGxldmVsIGFuZCBhZ2dyZWdhdGVkIHRvIGRldGVybWluZSBBSFUgYWlyIHZvbHVtZXMuDQoNCiMjIyBFbnRoYWxweSBDaGFuZ2UNCkFzIHRyZWF0bWVudCBjYW4gb2NjdXIgYXQgYm90aCB0aGUgQUhVIGFuZCBWQVYgYm94LCBlbnRoYXBseSBjaGFuZ2UgKGNoYW5nZSBpbiBlbmVyZ3kgZHVlIHRvIGhlYXRpbmcvY29vbGluZyBhbmQgaHVtaWRpdHkgcmVtb3ZhbCkgbXVzdCBiZSBjYWxjdWxhdGVkIGF0IGJvdGggc3RhZ2VzIGFuZCB0aGVuIGFnZ3JlZ2F0ZWQgdG8gZmluZCB0b3RhbCBlbnRoYWxweSBjaGFuZ2UgYXQgYSBnaXZlbiB0aW1lLiANCg0KIyMjIFdlYXRoZXIgRGF0YQ0KV2VhdGhlciBkYXRhIHdhcyBjb2xsZWN0ZWQgZnJvbSAqKk5lZWQgc291cmNlIGZvciB0aGlzIGRhdGEqKiB1c2luZyBhbiBBUEkgYW5kIHRoZW4gbWVyZ2VkIGludG8gdGhlIGRhdGEgdXNpbmcgdGhlIHRpbWVzLiBUaGUgbG9jYXRpb24gb2YgdGhpcyB3ZWF0aGVyIGRhdGEgaXMgKipUQkQqKiBhbmQgd2FzIHVzZWQgdG8gZXN0aW1hdGUgbG9jYWwgdGVtcGVyYXR1cmUsIHByZXNzdXJlLCBhbmQgcmVsYXRpdmUgaHVtaWRpdHkuICoqQ2hlY2sgdW5pdHMqKg0KDQojIyMgRXhwbG9yYXRpb24gb2YNCiMgUGxhbiBmb3IgQW5hbHlzaXMNClRoZSBwcmltYXJ5IGdvYWwgb2YgdGhpcyBhbmFseXNpcyBpcyB0byBnZW5lcmF0ZSBhbiBlZmZlY3RpdmUgbW9kZWwgb2YgaG93IEhWQUMgc3lzdGVtIG9wZXJhdGlvbiBhZmZlY3RzIGVuZXJneSBjb25zdW1wdGlvbiBvdmVyIHRpbWUsIHdoaWNoIGNhbiBiZSBkaXZpZGVkIGludG8gdGhyZWUgcGFydHM6DQoNCi0gQ2FsY3VsYXRlIGVzdGltYXRlZCBIVkFDIGVuZXJneSBjb25zdW1wdGlvbiB1c2luZyBoaXN0b3JpY2FsIGRhdGEgb24gb3BlcmF0aW9uYWwgbWV0cmljcw0KLSBWYWxpZGF0ZSBlc3RpbWF0ZWQgZW5lcmd5IGNvbnN1bXB0aW9uIHdpdGggaGlzdG9yaWNhbCwgYnVpbGRpbmctd2lkZSBlbmVyZ3kgY29uc3VtcHRpb24gZGF0YTsgdXBkYXRlIHBhcmFtZXRlcnMgYW5kIGFzc3VtcHRpb25zIGFzIG5lY2Vzc2FyeQ0KLSBDcmVhdGUgYSBzdGF0aXN0aWNhbCBtb2RlbCBvZiBlbmVyZ3kgY29uc3VtcHRpb24gaW4gdGhlIEhWQUMgc3lzdGVtIGFuZCBnZW5lcmF0ZSBhIGZvcmVjYXN0IHdpdGggdGhpcyBtb2RlbA0KDQoNCiMjICBDYWxjdWxhdGUgRW5lcmd5IFVzYWdlIGZyb20gSFZBQyBPcGVyYXRpb25hbCBNZXRyaWNzDQpUaGUgcHJpbWFyeSB1c2FnZXMgb2YgZW5lcmd5IGluIHRoaXMgSFZBQyBzeXN0ZW0gY29tZSBmcm9tIHRyZWF0bWVudCBhdCB0aGUgQUhVLCB0cmVhdG1lbnQgYXQgdGhlIFZBViBib3gsIGFuZCBmYW4gb3BlcmF0aW9uIGluIHRoZSBBSFUuIENhbGN1bGF0aW9ucyBmb3IgdHJlYXRtZW50IGF0IHRoZSBBSFUgYW5kIFZBViBib3ggbGV2ZWwgbGV2ZXJhZ2UgdGhlIHNhbWUgZXF1YXRpb25zLCBhbmQgZmFuIGVxdWF0aW9ucyBjYW4gYmUgbGV2ZXJhZ2VkIHRvIGVzdGltYXRlIGZhbiBlbmVyZ3kgdXNhZ2UuDQoNCiMjIyBBaXIgVHJlYXRtZW50DQpUaGUgY2hhbmdlIGluIGVuZXJneSBkdWUgdG8gYWlyIHRyZWF0bWVudCAoYXQgZWl0aGVyIEFIVSBvciBWQVYpIGNhbiBiZSBkaXZpZGVkIGludG8gbGF0ZW50IGFuZCBzZW5zaWJsZSBoZWF0LiBDaGFuZ2VzIGluIGxhdGVudCBoZWF0IGFyaXNlIGZyb20gaHVtaWRpdHkgYWRkZWQgb3IgcmVtb3ZlZCBmcm9tIHRoZSBhaXIgd2hlcmVhcyBzZW5zaWJsZSBoZWF0IGlzIGFmZmVjdGVkIGJ5IGNoYW5nZXMgaW4gYWlyIHRlbXBlcmF0dXJlLiBFbnRoYWxweSBjaGFuZ2UgYWNjb3VudHMgZm9yIGJvdGggbGF0ZW50IGFuZCBzZW5zaWJsZSBoZWF0IGFzIGlzIGNhbGN1bGF0ZWQgdXNpbmcgKipmaXggd2l0aCBab3Rlcm8qKiAoaHR0cHM6Ly9yZHJyLmlvL2dpdGh1Yi9jaHJyYXMvY2xpbWF0ZWVuZy9tYW4vKS4gRXF1YXRpb24gMSwgYmVsb3csIGNhbiB0aGVuIGJlIHVzZWQgdG8gZGV0ZXJtaW5lIHRvdGFsIGhlYXQgYnkgY29tYmluaW5nIGNhbGN1bGF0ZWQgZW50aGFscHkgY2hhbmdlIHdpdGggY29sbGVjdGVkIGRhdGEgb24gYWlyIHZvbHVtZSBmbG93Lg0KDQojIyMjIEVxdWF0aW9uIDEsIExhdGVudCBhbmQgU2Vuc2libGUgSGVhdA0KKipab3Rlcm8gc291cmNlKioNCmhfdCA9IM+BXCpxXCpkaA0KDQp3aGVyZToNCg0KaF90ID0gdG90YWwgaGVhdCAoa1cpXA0KcSA9IGFpciB2b2x1bWUgZmxvdyAobTMvcylcDQrPgSA9IGRlbnNpdHkgb2YgYWlyICgxLjIwMiBrZy9tMylcDQpkaCA9IGVudGhhbHB5IGRpZmZlcmVuY2UgKGtKL2tnKQ0KDQojIyMjIExvYWQgZGF0YQ0KYGBge3J9DQpsb2FkKCJDOlxcVXNlcnNcXGNhbmVhXFxEb2N1bWVudHNcXFVWQVxcU3ByaW5nIDIwMjFcXFRpbWVzZXJpZXNcXG5lYWxlLWNhbGViXFxkYXRhXFxwcmVDYWxjRGF0YS5SRGF0YSIpDQoNCmBgYA0KDQojIyMjIENhbGN1bGF0ZSBFbnRoYWxweSBmb3IgTWl4ZWQgYW5kIHN1cHBseSBBaXIsIHRoZW4gdG90YWwgaGVhdA0KYGBge3J9DQpsaWJyYXJ5KGNsaW1hdGVlbmcpDQoNCiNEZWZpbmUgY29uc3RhbnRzDQpSSGNvbnN0YW50ID0gMC4wMTANCmRlbnNpdHkgPSAxLjIwMg0KQ0ZNdG9NX1NDb252ZXJzdGlvbkZhY3RvciA9IDAuMDAwNDcxOTQ3NDUNCg0KIyBDYWxjdWxhdGUgQUhVIGxldmVsIGVudGhhbHB5DQplcXVpcCRTQUVudGhhbHB5ID0gZW50aGFscHkoZXF1aXAkU0FULCBSSGNvbnN0YW50KSANCmVxdWlwJE1BRW50aGFscHkgPSBlbnRoYWxweShlcXVpcCRNQVQsIFJIY29uc3RhbnQpDQplcXVpcCR0b3RhbEhlYXQgPSBhYnMoZXF1aXAkU0FFbnRoYWxweSAtZXF1aXAkTUFFbnRoYWxweSkqQ0ZNdG9NX1NDb252ZXJzdGlvbkZhY3RvciplcXVpcCRTQUYqZGVuc2l0eQ0KDQpgYGANCg0KIyMjIyBHZXQgaW5wdXQgYWlyIHRlbXAgZm9yIGVhY2ggcm9vbQ0KYGBge3J9DQojIGNyZWF0ZSB0YWJsZSBtYXBwaW5nIHJvb20gdG8gZXF1cG1lbnQgZnJvbSBzeXN0ZW0gZG9jdW1lbnRhdGlvbg0KQUhVXzJFIDwtIGMoMjQxLCAyNDMsIDI0NSwgMjQ3LCAyNDksIDI1MSwgMjUzLCAyNTcsIDI1NSwgMjU5LCAyNjMsIDI2MSwgMjQwLCAiQzI0NCIsIDI0NCwgMjYwLCAyMTMsIDIxNywgMjI1LCAyMTgsICJDMjMwIiwgMjIwLCAiQzIxMCIsICJUMjEyIiwgIlQyMTgiLCAiQzIxNiIsICJDMjE0IiwgIlQyMTAiLCAyNTYsIDIyOSwgMjMxLCAyMjMsICJDMjI3IiwgIkMyMTEiLCAyNTQsICJDMjUwIiwgMjU4LCAiQzIxMyIsIDIyMSkgDQoNCkFIVV8yVyA8LSBjKDI2OSwgMjY3LCAyNjUsIDI3MywgMjcxLCAyNzUsIDI3NywgMjc5LCAyODEsIDI4MywgMjg1LCAyNzQsIDI4NiwgMjA0LCAyMDgsIDI3MiwgMjcwLCAiQzI2MCIsICJDMjAwIiwgIkMyMDEiLCAyMDMsIDI3NiwgIkMyODAiLCAiQzI3MCIsIDIxMSwgMjAxKQ0KDQpyb29tc190YmwgPC0gcmJpbmQodGliYmxlKCdyb29tJyA9IEFIVV8yRSwgJ2VxdWlwbWVudCcgPSAiQUhVMkUiKSwgdGliYmxlKCdyb29tJyA9IEFIVV8yVywgJ2VxdWlwbWVudCcgPSAiQUhVMlciKSkNCg0KIyBleHRyYWN0IHJlbGV2YW50IGluZm9ybWF0aW9uIGZyb20gcm9vbSBjb2RpbmcNCnJvb21zJGNsZWFuZWRfcm9vbSA9IHN0cl9leHRyYWN0KHJvb21zJHJvb20sICJDXFxkezN9fF5cXGR7M30iKQ0KDQojIGdldCByZWxldmFudCBlcXVpcG1lbnQgZm9yIGVhY2ggcm9vbSANCnJvb21zID0gbGVmdF9qb2luKHJvb21zLCByb29tc190YmwsIGJ5PWMoImNsZWFuZWRfcm9vbSIgPSAicm9vbSIpKQ0KDQpyb29tcyAlPiUgZmlsdGVyKCFpcy5uYShyb29tKSkgLT4gcm9vbXMNCg0Kcm9vbXMgPSByb29tcyAlPiUgc2VsZWN0KC1jbGVhbmVkX3Jvb20pIC0+IHJvb21zDQoNCiMgZ2V0IGlucHV0IGFpciB0ZW1wZXJhdHVyZSBmb3IgZWFjaCByb29tDQpyZWwgPSBlcXVpcCAlPiUgc2VsZWN0KFNBVCkNCnJvb21zID0gbGVmdF9qb2luKHJvb21zLCByZWwsIGJ5PWMoImVxdWlwbWVudCIsICJ0aW1lIikpDQoNCiMgcmVuYW1lIGNvbHVtbnMgZm9yIGNsYXJpdHkNCmNvbG5hbWVzKHJvb21zKVszXSA9ICJvdXRwdXRUZW1wIg0KY29sbmFtZXMocm9vbXMpWzhdID0gImlucHV0VGVtcCINCg0KYGBgDQoNCiMjIyMgQ2FsY3VsYXRlIGVuZXJneSBjb25zdW1wdGlvbiBmcm9tIHJvb20gbGV2ZWwgdHJlYXRtZW50DQpgYGB7cn0NCnJvb21zJGlucHV0RW50aGFscHkgPSBlbnRoYWxweShyb29tcyRpbnB1dFRlbXAsIFJIY29uc3RhbnQpIA0Kcm9vbXMkb3V0cHV0RW50aGFscHkgPSBlbnRoYWxweShyb29tcyRvdXRwdXRUZW1wLCBSSGNvbnN0YW50KQ0Kcm9vbXMkdG90YWxIZWF0ID0gYWJzKHJvb21zJGlucHV0RW50aGFscHkgLSByb29tcyRvdXRwdXRFbnRoYWxweSkqQ0ZNdG9NX1NDb252ZXJzdGlvbkZhY3Rvcipyb29tcyRTQUYqZGVuc2l0eQ0KYGBgDQoNCiMjIyBGYW5zDQpQb3dlciB1c2VkIGJ5IGEgZmFuIGNhbiBiZSBjYWxjdWxhdGVkIHVzaW5nIGVxdWF0aW9uIDIsIGJlbG93LiBQcmVzc3VyZSBzZXQgdG8gYSBjb25zdGFudCB0eXBpY2FsIG9mIGNvbW1lcmNpYWwgSFZBQyBmYW5zLCBmYW4gZWZmaWNpZW5jeSB3aWxsIGJlIGFzc3VtZWQgdG8gYmUgNjAlLCBhbmQgYWlyIHZvbHVtZSBpcyBtZWFzdXJlZC4NCg0KIyMjIyBFcXVhdGlvbiAyLCBQb3dlciBVc2VkIGJ5IEZhbg0KKipab3Rlcm8gc291cmNlKioNClAgPSBkcCpxL211DQoNCndoZXJlOg0KDQptdSA9IGZhbiBlZmZpY2llbmN5ICh2YWx1ZXMgYmV0d2VlbiAwIC0gMSlcDQpkcCA9IHRvdGFsIHByZXNzdXJlIChQYSkgXA0KcSA9IGFpciB2b2x1bWUgZGVsaXZlcmVkIGJ5IHRoZSBmYW4gKG0zL3MpXA0KUCA9IHBvd2VyIHVzZWQgYnkgdGhlIGZhbiAoVywgTm0vcykNCg0KIyMjIyBGYW4gRW5lcmd5DQpgYGB7cn0NCiMgU2V0IGNvbnN0YW50cw0KZmFuRWZmaWNpZW5jeUNvZWYgPSAwLjYNCnByZXNzdXJlID0gNDAwMA0KV3RvX2tXID0xMDAwDQoNCiMgQ2FsY3VsYXRlIGVuZXJneSAoMiogZm9yIHR3byBmYW5zKQ0KZXF1aXAkZmFuRW5lcmd5ID0gMiplcXVpcCRTQUYqQ0ZNdG9NX1NDb252ZXJzdGlvbkZhY3RvcipwcmVzc3VyZS9mYW5FZmZpY2llbmN5Q29lZi9XdG9fa1cNCmBgYA0KDQoNCiMjIyBDcmVhdGUgdHNpYmJsZSB3aXRoIHJvb20gYW5kIEFIVSBoZWF0IGFuZCBGYW4gRW5lcmd5DQpgYGB7cn0NCnJvb21zICU+JSBncm91cF9ieShlcXVpcG1lbnQpICU+JSBzdW1tYXJpc2UodG90YWxIZWF0ID0gc3VtKHRvdGFsSGVhdCkpIC0+IHJvb21BSFVIZWF0DQoNCmVxdWlwICU+JSBzZWxlY3QodG90YWxIZWF0LCBmYW5FbmVyZ3kpICU+JSBpbm5lcl9qb2luKHJvb21BSFVIZWF0LCBieT1jKCJ0aW1lIiwgImVxdWlwbWVudCIpLCBzdWZmaXggPSBjKCIuQUhVIiwgIi5yb29tIikpIC0+IHRvdGFsRW5lcmd5REYNCg0KdG90YWxFbmVyZ3lERiR0b3RhbEhlYXQgPSB0b3RhbEVuZXJneURGJHRvdGFsSGVhdC5BSFUgKyB0b3RhbEVuZXJneURGJHRvdGFsSGVhdC5yb29tDQp0b3RhbEVuZXJneURGJHRvdGFsRW5lcmd5ID0gdG90YWxFbmVyZ3lERiR0b3RhbEhlYXQgKyB0b3RhbEVuZXJneURGJGZhbkVuZXJneQ0KYGBgDQoNCiMjIyBTZWFzb25hbGl0eSBvZiBFbmVyZ3kgQ29uc3VtcHRpb24NCmBgYHtyfQ0KdG90YWxFbmVyZ3lERiA9IGZpbGxfZ2Fwcyh0b3RhbEVuZXJneURGKQ0KZ2dfc2Vhc29uKHRvdGFsRW5lcmd5REYsIHRvdGFsRW5lcmd5LCBwZXJpb2QgPSAid2VlayIpDQpnZ19zZWFzb24odG90YWxFbmVyZ3lERiwgdG90YWxFbmVyZ3ksIHBlcmlvZCA9ICJkYXkiKQ0KZ2dfc2Vhc29uKHRvdGFsRW5lcmd5REYsIHRvdGFsRW5lcmd5LCBwZXJpb2QgPSAibW9udGgiKQ0KYGBgDQpFbmVyZ3kgY29uc3VtcHRpb24gaGFzIGEgY2xlYXIgZGFpbHkgY3ljbGUgd2hlcmUgdGhlIHN5c3RlbSBpcyBvZmYgb3ZlciBuaWdodCB0aGVuIHR1cm5zIG9uIGF0IGEgdGltZSBlYXJseSBlbm91Z2ggaW4gdGhlIG1vcm5pbmcgdG8gZW5zdXJlIHRoYXQgdGhlIGludGVybmFsIHRlbXBlcmF0dXJlIGluIHRoZSBidWlsZGluZyBtZWV0cyB0aGUgc2V0cG9pbnQgYnkgdGhlIHRpbWUgb2NjdXBhbnRzIGFycml2ZS4gVGhlIHNoaWZ0aW5nIHN0YXJ0IHRpbWVzIHRocm91Z2hvdXQgdGhlIHllYXIgYXMgc2VlbiBvbiB0aGUgZGFpbHkgc2Vhc29uYWwgcGxvdCBhcmUgYSByZXN1bHQgb2YgdGhpcyBjb250cm9sIG1lY2hhbmlzbSB3aGljaCBwcmVkaWN0cyBob3cgbG9uZyB0aGUgc3lzdGVtIHdpbGwgbmVlZCB0byBhcnJpdmUgYXQgdGhlIHNldHBvaW50IGdpdmVuIHRoZSBjdXJyZW50IGludGVybmFsIHRlbXBlcmF0dXJlIGFuZCBiZWdpbnMgdHJlYXRtZW50IGFjY29yZGluZ2x5LiBEdXJpbmcgY29sZGVyL3dhcm1lciBzZWFzb25zLCBpbnRlcm5hbCB0ZW1wZXJhdHVyZSBkcmlmdHMgZmFydGhlciBmcm9tIHRoZSBzZXRwb2ludCBvdmVybmlnaHQgYW5kIHRodXMgdGFrZXMgbG9uZ2VyIHRvIHJldHVybiB0byB0aGUgc2V0cG9pbnQuDQoNCkFIVTJXIGFwcGVhcnMgdG8gaGF2ZSBhIGxvd2VyIGJvdW5kIG9mIGVuZXJneSBjb25zdW1wdGlvbiBhYm92ZSB0aGF0IG9mIEFIVTJFLiBJbnZlc3RpZ2F0aW5nIHRoZSBjb21wb25lbnRzIG9mIHRvdGFsRW5lcmd5IHJldmVhbHMgdGhhdCB0aGlzIGxvd2VyIGJvdW5kIGNvbWVzIGZyb20gaW5jcmVhc2VkIG5pZ2h0dGltZSBmYW4gZW5lcmd5IGFuZCBBSFUgbGV2ZWwgZW5lcmd5IGNvbnN1bXB0aW9uLg0KYGBge3J9DQpnZ19zZWFzb24oZmlsbF9nYXBzKGVxdWlwKSwgZmFuRW5lcmd5LCBwZXJpb2QgPSAiZGF5IikgKyB5bGFiKCJGYW4gRW5lcmd5IChrVykiKQ0KZ2dfc2Vhc29uKGZpbGxfZ2Fwcyhyb29tQUhVSGVhdCksIHRvdGFsSGVhdCwgcGVyaW9kID0gImRheSIpICsgeWxhYigiUm9vbSBMZXZlbCBSZWhlYXQgRW5lcmd5IChrVykiKQ0KZ2dfc2Vhc29uKGZpbGxfZ2FwcyhlcXVpcCksIHRvdGFsSGVhdCwgcGVyaW9kID0gImRheSIpICsgeWxhYigiQUhVIExldmVsIFRyZWF0bWVudCBFbmVyZ3kgKGtXKSIpDQpgYGANCkJyZWFraW5nIGRvd24gZW5lcmd5IGNvbnN1bXB0aW9uIGluIHRoaXMgbWFubmVyIGFsc28gcmV2ZWFscyB0aGF0IGZhbiBlbmVyZ3kgY29uc3VtcHRpb24gZm9sbG93cyBhIGRhaWx5IGN5Y2xlIGJ1dCBpcyBub3QgYXMgc2lnbmlmaWNhbnRseSBpbmZsdWVuY2VkIGJ5IHRpbWUgb2YgeWVhciBhcyByb29tIG9yIEFIVSB0cmVhdG1lbnQgY29uc3VtcHRpb24uIEludGVyZXN0aW5nbHkgYXMgd2VsbCwgdGhvdWdoIGJvdGggQUhVIGFuZCByb29tIGVuZXJneSBjb25zdW1wdGlvbiBzaG93IGEgeWVhcmx5IHRyZW5kLCB0aGV5IGFwcGVhciB0byBiZSBuZWFybHkgaW52ZXJzZS4gUm9vbSBjb25zdW1wdGlvbiBpcyBoaWdoZXN0IG9uIGJsdWUgZGF5cyBhbmQgbG93ZXN0IG9uIHBpbmssIHdoaWxlIEFIVSBjb25zdW1wdGlvbiBhcHBlYXJzIHRvIGJlIGhpZ2hlc3Qgb24gb3JhbmdlIGFuZCBsb3dlc3Qgb24gYmx1ZS4NCg0KIyMjIEludmVzdGlnYXRlIHRyZW5kcyBpbiByZWxhdGl2ZSBlbmVyZ3kgY29uc3VtcHRpb24NCmBgYHtyfQ0KIyBnZXQgbG9uZ2Zvcm0gZGF0YSBmb3IgcGxvdHRpbmcNCnRvdGFsRW5lcmd5REYgJT4lIHNlbGVjdCgtdG90YWxIZWF0LCAtdG90YWxFbmVyZ3kpICU+JSBmaWx0ZXIoZXF1aXBtZW50ID09ICJBSFUyRSIpICU+JSBwaXZvdF9sb25nZXIoY29scyA9IGModG90YWxIZWF0LkFIVSwgZmFuRW5lcmd5LCB0b3RhbEhlYXQucm9vbSksIG5hbWVzX3RvID0gImRhdGFwb2ludCIsIHZhbHVlc190byA9ICJ2YWx1ZSIpIC0+IGxvbmdBSFUyRQ0KDQp0b3RhbEVuZXJneURGICU+JSBzZWxlY3QoLXRvdGFsSGVhdCwgLXRvdGFsRW5lcmd5KSAlPiUgZmlsdGVyKGVxdWlwbWVudCA9PSAiQUhVMlciKSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHRvdGFsSGVhdC5BSFUsIGZhbkVuZXJneSwgdG90YWxIZWF0LnJvb20pLCBuYW1lc190byA9ICJkYXRhcG9pbnQiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAtPiBsb25nQUhVMlcNCg0KIyBzdGFja2VkIGFyZWEgcGxvdHMNCmdncGxvdChkYXRhID0gbG9uZ0FIVTJXLCBhZXMoeD10aW1lLCB5PXZhbHVlLCBmaWxsPWRhdGFwb2ludCkpICsgZ2VvbV9hcmVhKCkNCmdncGxvdChkYXRhID0gbG9uZ0FIVTJFLCBhZXMoeD10aW1lLCB5PXZhbHVlLCBmaWxsPWRhdGFwb2ludCkpICsgZ2VvbV9hcmVhKCkNCg0KIyBwcm9wb3J0aW9uYWwgc3RhY2tlZCBhcmVhIHBsb3RzDQpnZ3Bsb3QobG9uZ0FIVTJXLCBhZXMoeD10aW1lLCB5PXZhbHVlLCBmaWxsPWRhdGFwb2ludCkpICsgDQogICAgZ2VvbV9hcmVhKHBvc2l0aW9uID0gImZpbGwiKSArIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiQmx1ZXMiKQ0KDQpnZ3Bsb3QobG9uZ0FIVTJFLCBhZXMoeD10aW1lLCB5PXZhbHVlLCBmaWxsPWRhdGFwb2ludCkpICsgDQogICAgZ2VvbV9hcmVhKHBvc2l0aW9uID0gImZpbGwiKSArIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiQmx1ZXMiKQ0KYGBgDQpJdCBhcHBlYXJzIHRoYXQgcm9vbSByZWhlYXRpbmcgdXNlcyBhIG11Y2ggbGFyZ2VyIHByb3BvcnRpb24gb2YgdGhlIGVuZXJneSBvZiB0aGUgc3lzdGVtIGluIG1vbnRocyB3aGVyZSBoZWF0aW5nIGlzIG1vcmUgbGlrZWx5IHRvIGJlIGFjdGl2ZSB0aGFuIGNvb2xpbmcgYW5kIHRoZSBwcm9wb3J0aW9uIG9mIGVuZXJneSBleHBlbmRlZCBvbiB0aGUgZmFucyBpbmNyZWFzZXMgZHJhbWF0aWNhbGx5IGFzIG92ZXJhbGwgc3lzdGVtIGVuZXJneSB1c2UgZGVjbGluZXMuIFRob3VnaCB3ZSBkb24ndCBoYXZlIGEgY29tcGxldGUgeWVhciBvZiBkYXRhLCBpdCBhcHBlYXJzIHNob3VsZGVyIHNlYXNvbnMgKGZhbGwvc3ByaW5nKSBjb25zdW1lIGxlc3MgZW5lcmd5IHRoYW4gd2ludGVyL3N1bW1lciwgaW4gbGluZSB3aXRoIHdoYXQgd2UgbWlnaHQgZXhwZWN0IGdpdmVuIG91dGRvb3IgdGVtcGVyYXR1cmVzLg0KDQojIyMgUmVsYXRpb25zaGlwIG9mIExvY2FsIFdlYXRoZXIgYW5kIEVuZXJneSBDb25zdW1wdGlvbg0KYGBge3J9DQp3ZWF0aGVyX21lcmdlID0gd2VhdGhlcg0KDQojIHNoaWZ0IHdlYXRoZXIgZGF0YSBieSBhIG1pbnV0ZSB0byBhbGxvdyBmb3IgbWVyZ2luZw0Kd2VhdGhlcl9tZXJnZSRvYnNUaW1lTG9jYWwgPSB3ZWF0aGVyX21lcmdlJG9ic1RpbWVMb2NhbCArIDYwDQoNCiMgbWVyZ2UgZGF0YQ0KbGVmdF9qb2luKHRvdGFsRW5lcmd5REYsIHdlYXRoZXJfbWVyZ2UsIGJ5PWMoInRpbWUiID0gIm9ic1RpbWVMb2NhbCIpKSAlPiUgZmlsdGVyKCFpcy5uYSh0b3RhbEVuZXJneSkpLT4gd2VhdGhlcl9lbmVyZ3kNCg0KIyBwbG90LCBmaWx0ZXJpbmcgb3V0IGxvdyBlbmVyZ3kgdmFsdWVzIGZvciB3aGVuIEhWQUMgc3lzdGVtIGlzICJvZmYiDQpnZ3Bsb3QoZGF0YSA9IHdlYXRoZXJfZW5lcmd5ICU+JSBmaWx0ZXIodG90YWxFbmVyZ3kgPiA1MCksIGFlcyh4PXRlbXBBdmcsIHk9dG90YWxFbmVyZ3kpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkNCmBgYA0KQXMgdGhlIHByZXZpb3VzIGNoYXJ0cyBzaG93aW5nIGxvd2VyIGNvbnN1bXB0aW9uIGluIHNob3VsZGVyIHNlYXNvbnMgaW1wbGllZCwgZW5lcmd5IGNvbnN1bXB0aW9uIGFwcGVhcnMgdG8gYmUgcm91Z2hseSBxdWFkcmF0aWMgd2l0aCByZXNwZWN0IHRvIHRlbXBlcmF0dXJlLiANCg0KIyMgVmFsaWRhdGlvbiBvZiBFc3RpbWF0ZWQgRW5lcmd5IENvbnN1bXB0aW9uDQpIaXN0b3JpY2FsIGRhdGEgaXMgYXZhaWxhYmxlIGZvciBidWlsZGluZy13aWRlIGVuZXJneSBjb25zdW1wdGlvbiwgZGl2aWRlZCBpbnRvOg0KDQotIGNoaWxsZWRXYXRlciAoY29vbGluZykNCi0gaGVhdGluZyANCi0gZWxlY3RyaWNpdHkNCg0KYGBge3J9DQpoZWFkKGJ1aWxkaW5nRW5lcmd5KQ0KYGBgDQoNCkFzIEhWQUMgb3BlcmF0aW9uIHJlcHJlc2VudHMgYSBzaWduaWZpY2FudCBwYXJ0IG9mIGJ1aWxkaW5nIGVuZXJneSBjb25zdW1wdGlvbiwgd2Ugd291bGQgZXhwZWN0IHRoYXQgdHJlbmRzIGluIGFuZCBjaGFuZ2VzIG9mIEhWQUMgc3lzdGVtIGVuZXJneSBjb25zdW1wdGlvbiB3b3VsZCBjbG9zZWx5IHRyYWNrIHdpdGggYnVpbGRpbmcgd2lkZSBlbmVyZ3kgY29uc3VtcHRpb24uIENhbGN1bGF0ZWQgaGlzdG9yaWNhbCBlbmVyZ3kgY29uc3VtcHRpb24gaXMgcGxvdHRlZCBuZXh0IHRvIGJ1aWxkaW5nLXdpZGUgZW5lcmd5IGNvbnN1bXB0aW9uIGZvciBpbnNwZWN0aW9uOg0KDQojIyMgRGV0ZXJtaW5lIGNvb2xpbmcgc3RhdGUgYW5kIGV2YWx1dGF0ZSByZWxhdGlvbnNoaXAgb2YgY2FsY3VsYXRlZCBlbmVyZ3kgY29uc3VtcHRpb24gaW4gY29vbGluZyBzdGF0ZSBhbmQgYWN0dWFsIGhpc3RvcmljYWwgY2hpbGxlZCB3YXRlciBjb25zdW1wdGlvbiANCmBgYHtyfQ0KbGlicmFyeShwbG90bHkpDQoNCmVxdWlwICU+JSBmaWx0ZXIoIWlzLm5hKFNBVCkgJiAhaXMubmEoTUFUKSkgLT4gZXF1aXBWZXJpZnkNCg0KIyBkZXRlcm1pbmUgY29vbGluZyBzdGF0dXMgYmFzZWQgb24gY29tcGFyYXRpdmUgdGVtcGVyYXR1cmUgb2YgaW5wdXQgYW5kIG91dHB1dCBhaXIgDQplcXVpcFZlcmlmeSA8LSBlcXVpcFZlcmlmeSAlPiUgbXV0YXRlKGNvb2xpbmcgPSANCiAgaWZfZWxzZSgNCiAgICBNQVQgPiBTQVQsIDEsIDANCiAgKQ0KKQ0KDQpsZWZ0X2pvaW4oZXF1aXBWZXJpZnksIGJ1aWxkaW5nRW5lcmd5LCBieT0idGltZSIpIC0+IGNvb2xpbmdWZXJpZnkNCg0KY29vbGluZ1ZlcmlmeSA8LSBjb29saW5nVmVyaWZ5ICU+JSBmaWx0ZXIoY29vbGluZyA9PSAxKSAlPiUgYXNfdHNpYmJsZShrZXkgPSBlcXVpcG1lbnQsIGluZGV4ID0gdGltZSkNCg0KIyBwbG90IGFuZCBtb2RlbCBhY3R1YWwgY29vbGluZyBlbmVyZ3kgY29uc3VtcHRpb24gYXMgYSBmdW5jaXRvbiBvZiBjYWxjdWFsdGVkIGhlYXRpbmcgY29uc3VtcHRpb24NCmdncGxvdChkYXRhID0gY29vbGluZ1ZlcmlmeSwgYWVzKHg9Y2hpbGxlZFdhdGVyLCB5PXRvdGFsSGVhdCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikNCg0KZmlnIDwtIHBsb3RfbHkoY29vbGluZ1ZlcmlmeSwgeCA9IH50aW1lLCB5ID0gfnRvdGFsSGVhdCwgbmFtZSA9ICdBSFUgSGVhdCcsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnKSANCmZpZyAlPiUgYWRkX3RyYWNlKHkgPSB+KGNoaWxsZWRXYXRlcioxMDAwKS8zNDEyLjE0MiwgbmFtZSA9ICdDaGlsbGVkIFdhdGVyJywgbW9kZSA9ICdsaW5lcycpDQoNCmNvb2xpbmdMTSA9IGxtKGNoaWxsZWRXYXRlcn50b3RhbEhlYXQsIGRhdGEgPSBjb29saW5nVmVyaWZ5KQ0KDQpzdW1tYXJ5KGNvb2xpbmdMTSkNCmBgYA0KQSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGNhbGN1bGF0ZWQgYW1vdW50IG9mIGVuZXJneSB1c2VkIGluIGNvb2xpbmcgYW5kIGhpc3RvcmljYWwgY2hpbGxlZCB3YXRlciBjb25zdW1wdGlvbiBhcHBlYXJzIHRvIGV4aXN0LCB0aG91Z2ggYSBsaW5lYXIgbW9kZWwgYmV0d2VlbiB0aGVzZSB0d28gcXVhbnRpdGllcyBzaG93cyBhbiBSXjIgb2YgMC4xODQ0LiBUaGlzIHN1Z2dlc3RzIHRoYXQgdHVuaW5nIHdpdGhpbiBzZXQgcGFyYW1ldGVycyB1c2VkIGluIGNhbGN1bGF0ZWQgZW5lcmd5IGNvbnN1bXB0aW9uIG1pZ2h0IGltcHJvdmUgdGhlIGFjY3VyYWN5IG9mIHRoZSBjYWxjdWxhdGlvbnMuDQoNCiMjIyBFdmFsdXRhdGUgcmVsYXRpb25zaGlwIG9mIGNhbGN1bGF0ZWQgZW5lcmd5IGNvbnN1bXB0aW9uIGluIGhlYXRpbmcgc3RhdGUgYW5kIGFjdHVhbCBoaXN0b3JpY2FsIGNoaWxsZWQgd2F0ZXIgY29uc3VtcHRpb24gDQpgYGB7cn0NCg0KIyBhZ2dyZWdhdGUgcm9vbSBsZXZlbCBjb250cmlidXRpb25zIHRvIGVuZXJneSBjb25zdW1wdGlvbiBieSBBSFUNCnJvb21zICU+JSBncm91cF9ieShlcXVpcG1lbnQpICU+JSBzdW1tYXJpc2UodG90YWxIZWF0ID0gc3VtKHRvdGFsSGVhdCkpIC0+IHJvb21BSFVIZWF0DQoNCiMgam9pbiAgcm9vbSBhbmQgZXF1aXBtZW50IGxldmVsIGRhdGENCmVxdWlwICU+JSBpbm5lcl9qb2luKHJvb21BSFVIZWF0LCBieT1jKCJ0aW1lIiwgImVxdWlwbWVudCIpLCBzdWZmaXggPSBjKCIuQUhVIiwgIi5yb29tIikpIC0+IHRvdGFsRW5lcmd5REYNCg0KIyBjcmVhdGUgREYgZm9yIGVuZXJ5IHZlcmlmaWNhaXRvbiBhbmQgZGV0ZXJtaW5lIGhlYXRpbmcgc3RhdHVzIGJhc2VkIG9uIGNvbXBhcmF0aXZlIHRlbXBlcmF0dXJlIG9mIGlucHV0IGFuZCBvdXRwdXQgYWlyDQp0b3RhbEVuZXJneURGICU+JSBmaWx0ZXIoIWlzLm5hKFNBVCkgJiAhaXMubmEoTUFUKSkgLT4gdG90YWxFbmVyZ3lERlZlcmlmeQ0KDQp0b3RhbEVuZXJneURGVmVyaWZ5IDwtIHRvdGFsRW5lcmd5REZWZXJpZnkgJT4lDQogIG11dGF0ZShpc0hlYXRpbmcgPSBpZl9lbHNlKA0KICAgIFNBVCA+IE1BVCwgMSwgMA0KICAgICkNCiAgKQ0KDQojIGpvaW4gaW4gYWN0dWFsIGVuZXJneSBjb25zdW1wdGlvbiBkYXRhDQpsZWZ0X2pvaW4odG90YWxFbmVyZ3lERlZlcmlmeSwgYnVpbGRpbmdFbmVyZ3ksIGJ5PSJ0aW1lIikgLT4gaGVhdGluZ1ZlcmlmeQ0KDQpoZWF0aW5nVmVyaWZ5ICU+JSBmaWx0ZXIoIWlzLm5hKGhlYXRpbmdWZXJpZnkkaXNIZWF0aW5nKSkgLT4gaGVhdGluZ1ZlcmlmeQ0KDQojIGNhbGN1bGF0ZSB0b3RhbCBoZWF0aW5nIGVuZXJneSBiYXNlZCBvbiBBSFUgaGVhdGluZyBzdGF0dXMgDQpoZWF0aW5nVmVyaWZ5IDwtIGhlYXRpbmdWZXJpZnkgJT4lDQogIG11dGF0ZShoZWF0RW5lcmd5Q2FsYyA9IGlmX2Vsc2UoDQogICAgaXNIZWF0aW5nID09IDEsIHRvdGFsSGVhdC5BSFUgKyB0b3RhbEhlYXQucm9vbSwgdG90YWxIZWF0LnJvb20NCiAgICApDQogICkNCg0KIyBwbG90IGFuZCBtb2RlbCBhY3R1YWwgaGVhdGluZyBlbmVyZ3kgY29uc3VtcHRpb24gYXMgYSBmdW5jaXRvbiBvZiBjYWxjdWFsdGVkIGhlYXRpbmcgY29uc3VtcHRpb24NCmdncGxvdChkYXRhID0gaGVhdGluZ1ZlcmlmeSwgYWVzKHg9aGVhdGluZywgeT1oZWF0RW5lcmd5Q2FsYykpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikNCg0KZmlnIDwtIHBsb3RfbHkoaGVhdGluZ1ZlcmlmeSwgeCA9IH50aW1lLCB5ID0gfmhlYXRFbmVyZ3lDYWxjLCBuYW1lID0gJ0FIVSBIZWF0JywgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycpIA0KDQojIGhlYXRpbmcgaXMgYWRqdXN0ZWQgZnJvbSBrQlRVIHRvIGtXDQpmaWcgJT4lIGFkZF90cmFjZSh5ID0gfihoZWF0aW5nKjEwMDApLzM0MTIuMTQyLCBuYW1lID0gJ0hlYXRpbmcnLCBtb2RlID0gJ2xpbmVzJykNCg0KaGVhdGluZ0xNID0gbG0oaGVhdGluZ35oZWF0RW5lcmd5Q2FsYywgZGF0YSA9IGhlYXRpbmdWZXJpZnkpDQoNCnN1bW1hcnkoaGVhdGluZ0xNKQ0KDQpgYGANCk1vZGVsaW5nIGFjdHVhbCBoZWF0IGVuZXJneSBjb25zdW1wdGlvbiBhcyBhIGxpbmVhciBmdW5jdGlvbiBvZiBjYWxjdWxhdGVkIGhlYXQgY29uc3VtcHRpb24gcmVzdWx0cyBpbiBhbiBSXjIgb2Ygb25seSANCjAuMDg0LCB0aG91Z2ggdGhlIG1vZGVsIHBlcmZvcm1zIGJldHRlciB0aGFuIHRoZSBudWxsLiANCg0KRnVydGhlciBpbnZlc3RpZ2F0aW9uIGlzIGNsZWFybHkgbmVlZGVkIHRvIGRldGVybWluZSB3aGV0aGVyIHRoZXJlIGFyZSBvdGhlciBzaWduaWZpY2FudCBjb250cmlidXRvcnMgdG8gY29uc3VtcHRpb24gb2YgaGVhdGluZyBhbmQgY29vbGluZyBlbmVyZ3kgd2l0aGluIHRoZSBidWlsZGluZywgb3IgaWYgdGhlIG1vZGVsIG5lZWRzIG1vcmUgZGV2ZWxvcG1lbnQgKHR1bmluZyBvZiBjb25zdGFudCBwYXJhbWV0ZXJzIHVzZWQgaW4gY2FsY2xhdGlvbnMgcG90ZW50aWFsbHkpLiBBcyBhIGZ1cnRoZXIgcG9pbnQgb2YgcmVzZWFyY2gsIGhhdmluZyBlbmVyZ3kgcmVhZGluZ3MgZGlyZWN0bHkgbWV0ZXJlZCBmcm9tIHRoZSBIVkFDIHVuaXQgd291bGQgbGlrZWx5IHByb3ZpZGUgc2lnbmlmaWNhbnRseSBtb3JlIGFjY3VyYXRlIGRhdGEsIGVzcGVjaWFsbHkgaWYgZGV2ZWxvcGluZyBhbiBpbXByb3ZlZCBjb250cm9sIG1lY2hhbmlzbSBpcyBldmVyIGF0dGVtcHRlZC4NCg0KDQojIEZvcm1hbCBtb2RlbCBvZiBkYXRhLWdlbmVyYXRpbmcgcHJvY2Vzcw0KR2l2ZW4gdGhlIHByZXZpb3VzbHkgc2hvd24gZGFpbHkgY3ljbGUgb2YgdGhlIGRhdGEsIHNob3VsZGVyIHNlYXNvbiBiZWhhdmlvdXIsIGFuZCBxdWFkcmF0aWMgcmVsYXRpb25zaGlwIHdpdGggbG9jYWwgdGVtcGVyYXRlLCByZWdyZXNzaW9uIHdpdGggQVJJTUEgZXJyb3JzIHNlZW1zIGEgcmVhc29uYWJsZSBwbGFjZSB0byBiZWdpbiB0byBtb2RlbCB0aGUgZGF0YSBnZW5lcmF0aW5nIHByb2Nlc3MgYmVoaW5kIHRvdGFsIGVuZXJneSB1c2UgaW4gdGhlIHN5c3RlbS4gDQoNCkFuIGludmVzdGlnYXRpb24gb2YgbGFncyBhbmQgYXV0b2NvcnJlbGF0aW9uIHdpbGwgcHJvdmlkZSB0aGUgYmFzaXMgZm9yIHRoZSBwYXJhbWV0ZXIgc2VsZWN0aW9uIG9mIHRoZSBBUklNQSBtb2RlbC4NCg0KIyMgTGFnIFBsb3RzDQpgYGB7cn0NCiMgcmV0cmVpdmUgY2xlYW5lZCBkYXRhLCBmaWxsIGdhcHMNCmxvYWQoIkM6L1VzZXJzL2NhbmVhL0RvY3VtZW50cy9VVkEvU3ByaW5nIDIwMjEvVGltZXNlcmllcy9uZWFsZS1jYWxlYi9kYXRhL2NsZWFuZWREYXRhLlJkYXRhIikNCnRvdGFsRW5lcmd5REYgPSB0b3RhbEVuZXJneURGICU+JSBmaWxsX2dhcHMoKQ0KDQp0b3RhbEVuZXJneURGICU+JSBzZWxlY3QodG90YWxFbmVyZ3kpICU+JSBmaWx0ZXIoZXF1aXBtZW50ID09ICJBSFUyRSIpICU+JSBnZ19sYWcoeT10b3RhbEVuZXJneSwgZ2VvbSA9ICJwb2ludCIpDQp0b3RhbEVuZXJneURGICU+JSBzZWxlY3QodG90YWxFbmVyZ3kpICU+JSBmaWx0ZXIoZXF1aXBtZW50ID09ICJBSFUyVyIpICU+JSBnZ19sYWcoeT10b3RhbEVuZXJneSwgZ2VvbSA9ICJwb2ludCIpDQpgYGANCg0KUG90ZW50aWFsbHkgZ2l2ZW4gdGhlIGxvd2VyIGJvdW5kIHByZXZpb3VzbHkgc2VlbiBvbiBBSFUyVyBlbmVyZ3kgY29uc3VtcHRpb24sIGEgc3Ryb25nZXIgcmVsYXRpb25zaGlwIGFwcGVhcnMgaW4gdGhlIGxhZ3Mgb2YgQUhVMkUgdGhhbiBBSFUyVy4gDQoNCiMjIEF1dG9jb3JyZWxhdGlvbiBQbG90cw0KYGBge3J9DQojIEFDRnMNCnRvdGFsRW5lcmd5REYgJT4lIGZpbHRlcihlcXVpcG1lbnQgPT0gIkFIVTJFIikgJT4lIEFDRih0b3RhbEVuZXJneSwgbGFnX21heCA9IDE0MCkgJT4lIGF1dG9wbG90KCkgKyB5bGFiKCJBSFUyRSBBQ0YiKQ0KdG90YWxFbmVyZ3lERiAlPiUgZmlsdGVyKGVxdWlwbWVudCA9PSAiQUhVMlciKSAlPiUgQUNGKHRvdGFsRW5lcmd5LCBsYWdfbWF4ID0gMTQwKSAlPiUgYXV0b3Bsb3QoKSArIHlsYWIoIkFIVTJXIEFDRiIpDQoNCiMgUEFDRnMNCnRvdGFsRW5lcmd5REYgJT4lIGZpbHRlcihlcXVpcG1lbnQgPT0gIkFIVTJFIikgJT4lIFBBQ0YodG90YWxFbmVyZ3ksIGxhZ19tYXggPSAxNDApICU+JSBhdXRvcGxvdCgpICsgeWxhYigiQUhVMkUgUEFDRiIpDQp0b3RhbEVuZXJneURGICU+JSBmaWx0ZXIoZXF1aXBtZW50ID09ICJBSFUyVyIpICU+JSBQQUNGKHRvdGFsRW5lcmd5LCBsYWdfbWF4ID0gMTQwKSAlPiUgYXV0b3Bsb3QoKSArIHlsYWIoIkFIVTJXIFBBQ0YiKQ0KYGBgDQpHaXZlbiBhIDQ4IHBlcmlvZCBsYWcgY29ycmVzcG9uZHMgdG8gb25lIGRheSwgdGhlIGJlaGF2aW91ciBzZWVuIGluIHRoZSBBQ0YgcGxvdHMgc2hvdyBleGFjdGx5IHdoYXQgd2UgbWlnaHQgZXhwZWN0OyBBQ0YgaXMgaGlnaGVzdCBhdCBtdWx0aXBsZXMgb2YgMjQgaG91cnMgZnJvbSBhIGdpdmVuIHBvaW50LiBQQUNGIHBsb3RzIGFsc28gc2hvdyBoaWdoZXN0IFBBQ0YgdmFsdWVzIGF0IGFib3V0IHRoZSAyNCBob3VyIG1hcmssIHRob3VnaCBhZGRpdGlvbmFsIDI0IGhvdXIgZXh0ZW5zaW9ucyBwcm92aWRlIHNpZ25pZmljYW50bHkgbGVzcyBpbmZvcm1hdGlvbi4gDQoNCkhvd2V2ZXIsIGdpdmVuIHRoZSBsaWtlbHkgeWVhcmx5IHNlYXNvbmFsaXR5IG9mIHRoZSBkYXRhLCBhbiBpbnZlc3RpZ2F0aW9uIGludG8gdGhlIGRpZmZlcmVuY2VzIG9mIHRoZSBkYXRhIGlzIG5lZWRlZC4NCg0KIyMgRGlmZmVyZW5jaW5nDQpgYGB7cn0NCnRvdGFsRW5lcmd5REYgJT4lIGZpbHRlcihlcXVpcG1lbnQgPT0gIkFIVTJFIikgJT4lIGdnX3RzZGlzcGxheShkaWZmZXJlbmNlKHRvdGFsRW5lcmd5KSwgcGxvdF90eXBlID0gInBhcnRpYWwiLCBsYWdfbWF4ID0gMTQwKQ0KdG90YWxFbmVyZ3lERiAlPiUgZmlsdGVyKGVxdWlwbWVudCA9PSAiQUhVMlciKSAlPiUgZ2dfdHNkaXNwbGF5KGRpZmZlcmVuY2UodG90YWxFbmVyZ3kpLCBwbG90X3R5cGUgPSAicGFydGlhbCIsIGxhZ19tYXggPSAxNDApDQpgYGANCiMjIFByZWxpbWluYXJ5IEFSSU1BIE1vZGVsaW5nDQpUaGUgQUNGIGlzIHN1Z2dlc3RpdmUgb2YgYW4gTUEoNTIpIG1vZGVsIHdoaWxlIHRoZSBQQUNGIHN1Z2dlc3RzIGFuIEFSKDU0KSBtb2RlbCwgc28gQVJJTUEoMCwgMSwgNTIpIGFuZCBBUklNQSg1NCwgMSwgMCkgd2lsbCBiZSBwYXJ0IG9mIHRoZSBpbml0aWFsbHkgZml0IG1vZGVscy4gSG93ZXZlciwgYSBtb3JlIGFwcHJvcHJpYXRlIGFwcHJvYWNoIHdvdWxkIGxpa2VseSBiZSBzZXR0aW5nIHRoZSBzZWFzb25hbGl0eSBvZiB0aGUgZGF0YSB0byBkYWlseSAoNDggcGVyaW9kcykgYW5kIGF0dGVtcHRpbmcgQVJJTUEgZnJvbSB0aGVyZS4gVGhpcyBtYXkgbm90IGFjY3VyYXRlbHkgYWRkcmVzcyB5ZWFybG9uZyBzZWFzb25hbCB0cmVuZHMsIGJ1dCB3ZWF0aGVyIGRhdGEgbWF5IGFjY291bnQgZm9yIHRoaXMgaW4gYSBzeW5hbWljIHJlZ3Jlc3Npb24gbW9kZWwuDQoNCmBgYHtyfQ0KIyBjcmVhdGUgdW5pdmFyaWF0ZSBUUyBvYmplY3QgYW5kIGluZm9ybSBpdCBvZiA0OCBwZXJpb2Qgc2Vhc29uYWxpdHkNCnVuaXZhciA9IHRzKHRvdGFsRW5lcmd5REYsIGZyZXF1ZW5jeSA9IDQ4KVssN10NCg0KIyBjcmVhdGUgbW9kZWwgYW5kIGZvcmVjYXN0IGZvciAxMDAgZGF5cw0KYXV0by5hcmltYSh1bml2YXIpIC0+IHVuaXZhckFSSU1BDQpVQWZjIDwtIGZvcmVjYXN0KHVuaXZhckFSSU1BLCBoPTQ4MDApDQoNCiMgcGxvdCBmb3JlY2FzdA0KcGxvdChVQWZjLCB4bGltPWMoNTQwLCA2MDApLCB5bGltPWMoMCwxNzUpKQ0KDQpgYGANClRoaXMgbW9kZWwgc2VlbXMgdG8gY2FwdHVyZSB0aGUgZGFpbHkgY3ljbGUgb2YgZW5lcmd5IGNvbnN1bXB0aW9uIHF1aXRlIHdlbGwsIGJ1dCBkb2Vzbid0IHdlbGwgYWNjb3VudCBmb3IgdGhlIGluZmx1ZW5jZSBvZiB0ZW1wZXJhdHVyZSBvciB0aGUgZ2VuZXJhbCB2YXJpYXRpb24gaW4gdGhlIGRhdGEuIFRvIGRldGVybWluZSBpZiBhbm90aGVyIEFSSU1BIG1vZGVsIHdvdWxkIHBlcmZvcm0gYmV0dGVyLCBJJ2xsIHVzZSBmYWJsZTo6QVJJTUEgdG8gaW52ZXN0aWdhdGUgdGhyZWUgYWRkaXRpb25hbCBBUklNQSBtb2RlbHMgYmVmb3JlIGF0dGVtcHRpbmcgZHluYW1pYyByZWdyZXNzaW9uIHdpdGggQVJJTUEgZXJyb3JzLg0KDQojIyBBUklNQSBNb2RlbCBTZWFyY2gNCg0KYGBge3J9DQoNCiMgQ3JlYXRlIG1vZGVscyB1c2luZyBmYWJsZTo6QVJJTUEgZm9yIGJldHRlciBwbG90dGluZyBpbnRlcmZhY2UNCm1vZGVscyA8LSB0b3RhbEVuZXJneURGICU+JSANCiAgZmlsdGVyKGVxdWlwbWVudCA9PSAiQUhVMkUiKSAlPiUgDQogIG1vZGVsKHN0ZXB3aXNlID0gQVJJTUEodG90YWxFbmVyZ3kpLA0KICAgICAgICBzZWFyY2ggPSBBUklNQSh0b3RhbEVuZXJneSwgc3RlcHdpc2UgPSBGQUxTRSksDQogICAgICAgIHNlYXNvbmFsID0gQVJJTUEodG90YWxFbmVyZ3kgfiBQRFEocGVyaW9kPTQ4KSkpDQoNCm1vZGVscyAlPiUgc2VsZWN0KHNlYXNvbmFsKSAtPiBzZWFzb25hbA0KbW9kZWxzICU+JSBzZWxlY3Qoc3RlcHdpc2UpIC0+IHN0ZXB3aXNlDQptb2RlbHMgJT4lIHNlbGVjdChzZWFyY2gpIC0+IHNlYXJjaA0KDQojIHBsb3RzIHJlc2lkdWFscw0Kc2Vhc29uYWwgJT4lIGdnX3RzcmVzaWR1YWxzKCkNCnN0ZXB3aXNlICU+JSBnZ190c3Jlc2lkdWFscygpDQpzZWFyY2ggJT4lIGdnX3RzcmVzaWR1YWxzKCkNCg0KIyB3ZWVrbHkgc2Vhc29uYWwgcGxvdCBvZiByZXNpZHVhbHMNCnJlc2lkdWFscyhzZWFzb25hbCkgJT4lDQogIGFzX3RzaWJibGUoa2V5PS5tb2RlbCwgaW5kZXg9dGltZSkgJT4lDQogIGdnX3NlYXNvbih5PS5yZXNpZCwgcGVyaW9kID0gIndlZWsiKQ0KDQpyZXNpZHVhbHMoc3RlcHdpc2UpICU+JQ0KICBhc190c2liYmxlKGtleT0ubW9kZWwsIGluZGV4PXRpbWUpICU+JQ0KICBnZ19zZWFzb24oeT0ucmVzaWQsIHBlcmlvZCA9ICJ3ZWVrIikNCg0KcmVzaWR1YWxzKHNlYXJjaCkgJT4lDQogIGFzX3RzaWJibGUoa2V5PS5tb2RlbCwgaW5kZXg9dGltZSkgJT4lDQogIGdnX3NlYXNvbih5PS5yZXNpZCwgcGVyaW9kID0gIndlZWsiKQ0KYGBgDQpJdCBhcHBlYXJzIHRoZSBzZWFzb25hbCBtb2RlbCBoYXMgcmVzaWR1YWxzIHdoaWNoIGFyZSB0aGUgbW9zdCBub3JtYWxseSBkaXN0cmlidXRlZCBhbmQgd2hpY2ggbW9zdCBhcHByb2FjaCB3aGl0ZSBub2lzZS4gU2Vhc29uYWwgcGxvdHMgYWxzbyBzaG93IG1vcmUgYmFsYW5jZSBjb21wYXJlZCB0byB0aGUgbGFyZ2Ugc3Bpa2VzIGF0IHRoZSBiZWdpbm5pbmcgYW5kIGVuZCBvZiBlYWNoIGRheSBpbiB0aGUgc2VhcmNoIGFuZCBzdGVwd2lzZSBtb2RlbHMuIEV2YWx1YXRpbmcgZm9yZWNhc3RzIGdpdmVzIGEgY2xlYXJlciBwaWN0dXJlLg0KDQpgYGB7cn0NCnNlYXJjaCAlPiUgZm9yZWNhc3QoaD00ODApIC0+IHNlYXJjaEZDDQpzdGVwd2lzZSAlPiUgZm9yZWNhc3QoaD00ODApIC0+IHN0ZXB3aXNlRkMNCnNlYXNvbmFsICU+JSBmb3JlY2FzdChoPTQ4MCkgLT4gc2Vhc29uYWxGQw0KDQpzZWFyY2hGQyAlPiUgYXV0b3Bsb3QoKQ0Kc3RlcHdpc2VGQyAlPiUgYXV0b3Bsb3QoKQ0Kc2Vhc29uYWxGQyAlPiUgYXV0b3Bsb3QoKQ0KYGBgDQpPbmx5IHRoZSBtb2RlbCB3aXRoIGEgNDggc2Vhc29uYWwgdGVybSBjYXB0dXJlcyBhbnkgb2YgdGhlIGRhaWx5IGN5Y2xlIGluIHRoZSBkYXRhLCB3aGVyZWFzIHRoZSBvdGhlciB0d28gbW9kZWxzIHNlZW1zIHRvIHRha2UgYSBibGluZCBndWVzcyBhdCB0aGUgbWVhbiB2YWx1ZSBvZiB0aGUgcHJvY2Vzcy4NCg0KIyMgRHluYW1pYyBSZWdyZXNzaW9uIHdpdGggQVJJTUEgRXJyb3JzDQoNClRoZSBBUklNQSBtb2RlbCBzZWVtcyB0byBjYXB0dXJlIHRoZSBkYWlseSBjeWNsZSBpbiB0aGUgZGF0YSB3ZWxsLCBidXQgZGFpbHkgYW5kIHNlYXNvbmFsIHZhcmlhdGlvbiBleGlzdHMgYW5kIHRoaXMgdmFyaWF0aW9uIGNvdWxkIGxpa2VseSBiZSBleHBsYWluZWQgYnkgZGFpbHkgYW5kIHNlYXNvbmFsIGNoYW5nZXMgaW4gb3V0ZG9vciB0ZW1wZXJhdHVyZXMuIFRvIGNhcHR1cmUgdGhpcyB2YXJpYXRpb24sIGR5bmFtaWMgcmVncmVzc2lvbiB3aXRoIEFSSU1BIGVycm9yIGNhbiBiZSBhcHBsaWVkLiANCmBgYHtyfQ0KIyBOT1RFOiBPbiBteSBtYWNoaW5lLCB0aGVzZSBtb2RlbHMgdGFrZXMgYSB3aGlsZSB0byB0cmFpbiAoYWJvdXQgMjAtMzAgbWludXRlcykuIFNhdmVkIHZlcnNpb25zIG9mIHRoZSBtb2RlbHMgYXJlIHNhdmVkIGluIHRoZSAibW9kZWxzIiBmb2xkZXIgaW4gdGhpcyByZXBvc2l0b3J5IGFuZCBjYW4gYmUgbG9hZGVkIHVzaW5nICJsb2FkKCdtb2RlbHMvW21vZGVsbmFtZV0uUkRhdGEnKSIgZm9yIGZhc3RlciBjb21wdXRpbmcuDQoNCmR5blJlZyA8LSB3ZWF0aGVyX2VuZXJneSAlPiUgDQogIGZpbGxfZ2FwcygpICU+JQ0KICBmaWx0ZXIoZXF1aXBtZW50ID09ICJBSFUyRSIpICU+JSANCiAgbW9kZWwoQVJJTUEodG90YWxFbmVyZ3kgfiB0ZW1wQXZnICsgSSh0ZW1wQXZnXjIpICsgUERRKHBlcmlvZD00OCkpKQ0KDQpyZXBvcnQoZHluUmVnKQ0KDQpkeW5SZWcgJT4lIGdnX3RzcmVzaWR1YWxzKCkNCg0KcmVzaWR1YWxzKGR5blJlZykgJT4lDQogIGFzX3RzaWJibGUoa2V5PS5tb2RlbCwgaW5kZXg9dGltZSkgJT4lDQogIGdnX3NlYXNvbih5PS5yZXNpZCwgcGVyaW9kID0gIndlZWsiKQ0KDQpkeW5SZWdUcmFpbiA8LSB3ZWF0aGVyX2VuZXJneSAlPiUgDQogIGZpbGxfZ2FwcygpICU+JQ0KICBmaWx0ZXIoZXF1aXBtZW50ID09ICJBSFUyRSIpICU+JSANCiAgZmlsdGVyKHRpbWUgPCBkbXlfaCgiMS0wNC0yMDIxIDAwIikpICU+JQ0KICBtb2RlbChBUklNQSh0b3RhbEVuZXJneSB+IHRlbXBBdmcgKyBJKHRlbXBBdmdeMikgKyBQRFEocGVyaW9kPTQ4KSkpDQoNCmR5blJlZ2ZjIDwtIGZvcmVjYXN0KGR5blJlZ1RyYWluLCBuZXdfZGF0YSA9IHdlYXRoZXJfZW5lcmd5ICU+JSANCiAgZmlsbF9nYXBzKCkgJT4lDQogIGZpbHRlcihlcXVpcG1lbnQgPT0gIkFIVTJFIikgJT4lIA0KICBmaWx0ZXIodGltZSA+PSBkbXlfaCgiMS0wNC0yMDIxIDAwIikpKQ0KDQpyZXBvcnQoZHluUmVnVHJhaW4pDQoNCmR5blJlZ1RyYWluICU+JSBnZ190c3Jlc2lkdWFscygpDQoNCnJlc2lkdWFscyhkeW5SZWdUcmFpbikgJT4lDQogIGFzX3RzaWJibGUoa2V5PS5tb2RlbCwgaW5kZXg9dGltZSkgJT4lDQogIGdnX3NlYXNvbih5PS5yZXNpZCwgcGVyaW9kID0gIndlZWsiKQ0KDQphdXRvcGxvdChkeW5SZWdmYywgd2VhdGhlcl9lbmVyZ3kgJT4lIGZpbHRlcih0aW1lID49IGRteV9oKCIxLTA0LTIwMjEgMDAiKSkpDQpgYGANClRoaXMgZHluYW1pYyByZWdyZXNzaW9uIG1vZGVsIHNlZW1zIHRvIGJlIHRoZSBiZXN0IGF0IGNhcHR1cmluZyBhZGRpdGlvbmFsIGRhaWx5IHZhcmlhdGlvbiB3aGljaCBtYXkgYmUgYXR0cmlidXRlZCB0byB0ZW1wZXJhdHVyZS4gTG9va2luZyBhdCB0aGUgcmVzaWR1YWxzIG9uIGEgd2Vla2x5IGJhc2lzaSBvdmVyIHRoZSB5ZWFyLCBpdCBjYW4gYmUgc2VlbiB0aGF0IHRoZSB5ZWFybHkgc2Vhc29uYWwgY29tcG9uZW50IGlzIG5vdCBiZWluZyBjb21wbGV0ZWx5IGFjY291bnRlZCBmb3IsIGVzcGVjaWFsbHkgaW4gdGhlIGNoYW5naW5nIHN0YXJ0dXAgdGltZSBvZiB0aGUgc3lzdGVtIG92ZXIgdGhlIGNvdXJzZSBvZiB0aGUgeWVhci4NCg0KIyMgTW9kZWwgb2YgdGhlIERhdGEgR2VuZXJhdGluZyBQcm9jZXNzDQpUaGUgZGF0YSBnZW5lcmF0aW5nIHByb2Nlc3MgZm9yIHN5c3RlbSBlbmVyZ3kgY29uc3VtcHRpb24gY2FuIGJlIG1vZGVsZWQgYXMgYSBkeW5hbWljIHJlZ3Jlc3Npb24gd2l0aCBBUklNQSBlcnJvcnMgaW4gdGhlIGZvcm06DQoNCnkgPSDOsl8wICsgzrJfMVwqdGVtcEF2ZyArIM6yXzJcKnRlbXBBdmdeMiArIM61DQoNCndoZXJlIM61IGlzIEFSSU1BICg1LDAsMCwpKDEsMSwwKVs0OF0NCg0KDQojIERpc2N1c3Npb24gb2YgdGhlIHN0YXRpc3RpY2FsIG1vZGVsDQoNCg0KRGVzY3JpYmUgaG93IHRoZSBmb3JtYWwgc3RhdGlzdGljYWwgbW9kZWwgY2FwdHVyZXMgYW5kIGFsaWducyB3aXRoIHRoZSBuYXJyYXRpdmUgb2YgdGhlIGRhdGEtZ2VuZXJhdGluZyBwcm9jZXNzLg0KRmxhZyBhbnkgc3RhdGlzdGljYWwgY2hhbGxlbmdlcyByYWlzZWQgYnkgdGhlIGRhdGEgZ2VuZXJhdGluZyBwcm9jZXNzLCBlLmcuDQpzZWxlY3Rpb24gYmlhczsgc3Vydml2b3JzaGlwIGJpYXMNCm9taXR0ZWQgdmFyaWFibGVzIGJpYXMNCmV0Yy4NCg0KDQojIFJlZmVyZW5jZXMNCg0KDQoNCg0KDQojIExpbmtzIHRvIHNvdXJjZXMNCi0gVVMgRE9FIFJlcG9ydDogaHR0cHM6Ly93d3cuZW5lcmd5Lmdvdi9zaXRlcy9wcm9kL2ZpbGVzLzIwMTcvMTIvZjQ2L2J0by1ET0UtQ29tbS1IVkFDLVJlcG9ydC0xMi0yMS0xNy5wZGYgDQotIEJUVSBmb3JtdWxhZTogDQogIC0gaHR0cHM6Ly93d3cuYWR2YW50YWdlZW5naW5lZXJpbmcuY29tL2Z5aS8yODgvcGRmL2FkdmFudGFnZUluZHVzdHJpYWxGb3JtdWxhcy5wZGYNCiAgLSBodHRwczovL3d3dy5lbmdpbmVlcmluZ3Rvb2xib3guY29tL2Nvb2xpbmctaGVhdGluZy1lcXVhdGlvbnMtZF83NDcuaHRtbA0KICAtIGh0dHBzOi8vd3d3LmVuZXJneXZhbmd1YXJkLmNvbS9ibG9nL2NvbnZlcnRpbmctaGVhdGluZy1hbmQtY29vbGluZy1sb2Fkcy1haXItZmxvdy1waHlzaWNzDQotIFN1cHBseSBBaXIgVGVtcGVyYXR1cmU6IGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3RvcGljcy9lbmdpbmVlcmluZy9zdXBwbHktYWlyLXRlbXBlcmF0dXJlDQotIEdlbmVyYWwgcmVhZGluZ3M6DQogIC0gaHR0cHM6Ly9vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvZnVsbC8xMC4xMTExL2luYS4xMjQ5Nj9jYXNhX3Rva2VuPVdYWlZDRG5OTjlBQUFBQUElM0EteXhYaHF0UlJ6QmpZNWJOUm5PZndmSXBEcmJ4TFd4dmFGV0ZlOVRNdDE3UGJpbTV1eGdLUW40UjhFcUR2RERhRTNtVTRzdlNJeHZvOUdQMg0KICAtIGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzE0NzQ2NjcwMTY0NDA4ODcNCiAgLSBodHRwczovL3d3dy5zY2llbmNlZGlyZWN0LmNvbS9zY2llbmNlL2FydGljbGUvcGlpL1MxMzY0MDMyMTEzMDA0MzIyP2Nhc2FfdG9rZW49VURiUFpidGN1WndBQUFBQTphUi1oUEtaX1AtZUVaZHNrM25PX3BqS1ZtVXVtNFJLcWpEaTQzSnA0LW1URDlNcUFjNUJoSkZvN1hHNGIycXdObzBGTHdwZnZtV0UNCiAgLSBodHRwczovL3d3dy5laWEuZ292L2VuZXJneWV4cGxhaW5lZC91cy1lbmVyZ3ktZmFjdHMvDQoNCg0KDQo=